Message ID | 20191126083917.5995-7-stefan.bader@canonical.com |
---|---|
State | New |
Headers | show |
Series | Multiple buffer overflows in Marvell driver | expand |
On 26.11.19 09:39, Stefan Bader wrote: > From: qize wang <wangqize888888888@gmail.com> > > mwifiex_process_tdls_action_frame() without checking > the incoming tdls infomation element's vality before use it, > this may cause multi heap buffer overflows. > > Fix them by putting vality check before use it. > > Signed-off-by: qize wang <wangqize888888888@gmail.com> CVE-2019-14901 > > (backported from https://patchwork.kernel.org/patch/11257535/) > [smb: drop marvell subdirectory from path, plus manual context > adjustments] > Signed-off-by: Stefan Bader <stefan.bader@canonical.com> > --- > drivers/net/wireless/mwifiex/tdls.c | 69 ++++++++++++++++++++++++++--- > 1 file changed, 63 insertions(+), 6 deletions(-) > > diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c > index 9275f9c3f869..de59251158ad 100644 > --- a/drivers/net/wireless/mwifiex/tdls.c > +++ b/drivers/net/wireless/mwifiex/tdls.c > @@ -910,59 +910,116 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, > > switch (*pos) { > case WLAN_EID_SUPP_RATES: > + if (pos[1] > 32) > + return; > sta_ptr->tdls_cap.rates_len = pos[1]; > for (i = 0; i < pos[1]; i++) > sta_ptr->tdls_cap.rates[i] = pos[i + 2]; > break; > > case WLAN_EID_EXT_SUPP_RATES: > + if (pos[1] > 32) > + return; > basic = sta_ptr->tdls_cap.rates_len; > + if (pos[1] > 32 - basic) > + return; > for (i = 0; i < pos[1]; i++) > sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; > sta_ptr->tdls_cap.rates_len += pos[1]; > break; > case WLAN_EID_HT_CAPABILITY: > - memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos, > + if (pos > end - sizeof(struct ieee80211_ht_cap) - 2) > + return; > + if (pos[1] != sizeof(struct ieee80211_ht_cap)) > + return; > + /* copy the ie's value into ht_capb*/ > + memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2, > sizeof(struct ieee80211_ht_cap)); > sta_ptr->is_11n_enabled = 1; > break; > case WLAN_EID_HT_OPERATION: > - memcpy(&sta_ptr->tdls_cap.ht_oper, pos, > + if (pos > end - > + sizeof(struct ieee80211_ht_operation) - 2) > + return; > + if (pos[1] != sizeof(struct ieee80211_ht_operation)) > + return; > + memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2, > sizeof(struct ieee80211_ht_operation)); > break; > case WLAN_EID_BSS_COEX_2040: > + if (pos > end - 3) > + return; > + if (pos[1] != 1) > + return; > sta_ptr->tdls_cap.coex_2040 = pos[2]; > break; > case WLAN_EID_EXT_CAPABILITY: > + if (pos > end - sizeof(struct ieee_types_header)) > + return; > + if (pos[1] < sizeof(struct ieee_types_header)) > + return; > + if (pos[1] > 8) > + return; > memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, > sizeof(struct ieee_types_header) + > min_t(u8, pos[1], 8)); > break; > case WLAN_EID_RSN: > + if (pos > end - sizeof(struct ieee_types_header)) > + return; > + if (pos[1] < sizeof(struct ieee_types_header)) > + return; > + if (pos[1] > IEEE_MAX_IE_SIZE - > + sizeof(struct ieee_types_header)) > + return; > memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, > sizeof(struct ieee_types_header) + > min_t(u8, pos[1], IEEE_MAX_IE_SIZE - > sizeof(struct ieee_types_header))); > break; > case WLAN_EID_QOS_CAPA: > + if (pos > end - 3) > + return; > + if (pos[1] != 1) > + return; > sta_ptr->tdls_cap.qos_info = pos[2]; > break; > case WLAN_EID_VHT_OPERATION: > - if (priv->adapter->is_hw_11ac_capable) > - memcpy(&sta_ptr->tdls_cap.vhtoper, pos, > + if (priv->adapter->is_hw_11ac_capable) { > + if (pos > end - > + sizeof(struct ieee80211_vht_operation) - 2) > + return; > + if (pos[1] != > + sizeof(struct ieee80211_vht_operation)) > + return; > + /* copy the ie's value into vhtoper*/ > + memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2, > sizeof(struct ieee80211_vht_operation)); > + } > break; > case WLAN_EID_VHT_CAPABILITY: > if (priv->adapter->is_hw_11ac_capable) { > - memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos, > + if (pos > end - > + sizeof(struct ieee80211_vht_cap) - 2) > + return; > + if (pos[1] != sizeof(struct ieee80211_vht_cap)) > + return; > + /* copy the ie's value into vhtcap*/ > + memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2, > sizeof(struct ieee80211_vht_cap)); > sta_ptr->is_11ac_enabled = 1; > } > break; > case WLAN_EID_AID: > - if (priv->adapter->is_hw_11ac_capable) > + if (priv->adapter->is_hw_11ac_capable) { > + if (pos > end - 4) > + return; > + if (pos[1] != 2) > + return; > sta_ptr->tdls_cap.aid = > le16_to_cpu(*(__le16 *)(pos + 2)); > + } > + break; > default: > break; > } >
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 9275f9c3f869..de59251158ad 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -910,59 +910,116 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, switch (*pos) { case WLAN_EID_SUPP_RATES: + if (pos[1] > 32) + return; sta_ptr->tdls_cap.rates_len = pos[1]; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[i] = pos[i + 2]; break; case WLAN_EID_EXT_SUPP_RATES: + if (pos[1] > 32) + return; basic = sta_ptr->tdls_cap.rates_len; + if (pos[1] > 32 - basic) + return; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; sta_ptr->tdls_cap.rates_len += pos[1]; break; case WLAN_EID_HT_CAPABILITY: - memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos, + if (pos > end - sizeof(struct ieee80211_ht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_cap)) + return; + /* copy the ie's value into ht_capb*/ + memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2, sizeof(struct ieee80211_ht_cap)); sta_ptr->is_11n_enabled = 1; break; case WLAN_EID_HT_OPERATION: - memcpy(&sta_ptr->tdls_cap.ht_oper, pos, + if (pos > end - + sizeof(struct ieee80211_ht_operation) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_operation)) + return; + memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2, sizeof(struct ieee80211_ht_operation)); break; case WLAN_EID_BSS_COEX_2040: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.coex_2040 = pos[2]; break; case WLAN_EID_EXT_CAPABILITY: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > 8) + return; memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], 8)); break; case WLAN_EID_RSN: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header)) + return; memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.qos_info = pos[2]; break; case WLAN_EID_VHT_OPERATION: - if (priv->adapter->is_hw_11ac_capable) - memcpy(&sta_ptr->tdls_cap.vhtoper, pos, + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - + sizeof(struct ieee80211_vht_operation) - 2) + return; + if (pos[1] != + sizeof(struct ieee80211_vht_operation)) + return; + /* copy the ie's value into vhtoper*/ + memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2, sizeof(struct ieee80211_vht_operation)); + } break; case WLAN_EID_VHT_CAPABILITY: if (priv->adapter->is_hw_11ac_capable) { - memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos, + if (pos > end - + sizeof(struct ieee80211_vht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_vht_cap)) + return; + /* copy the ie's value into vhtcap*/ + memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2, sizeof(struct ieee80211_vht_cap)); sta_ptr->is_11ac_enabled = 1; } break; case WLAN_EID_AID: - if (priv->adapter->is_hw_11ac_capable) + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - 4) + return; + if (pos[1] != 2) + return; sta_ptr->tdls_cap.aid = le16_to_cpu(*(__le16 *)(pos + 2)); + } + break; default: break; }