]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mwifiex: Fix heap overflow in mwifiex_uap_parse_tail_ies()
authorTakashi Iwai <tiwai@suse.de>
Fri, 31 May 2019 13:18:41 +0000 (15:18 +0200)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 9 Jul 2019 21:04:22 +0000 (22:04 +0100)
commit 69ae4f6aac1578575126319d3f55550e7e440449 upstream.

A few places in mwifiex_uap_parse_tail_ies() perform memcpy()
unconditionally, which may lead to either buffer overflow or read over
boundary.

This patch addresses the issues by checking the read size and the
destination size at each place more properly.  Along with the fixes,
the patch cleans up the code slightly by introducing a temporary
variable for the token size, and unifies the error path with the
standard goto statement.

Reported-by: huangwen <huangwen@venustech.com.cn>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
[bwh: Backported to 3.16:
 - The tail IEs are parsed in mwifiex_set_mgmt_ies, which looks for two
   specific IEs rather than looping
 - Check IE length against tail length after calling
   cfg80211_find_vendor_ie(), but not after cfg80211_find_ie() since that
   already does it
 - On error, return without calling mwifiex_set_mgmt_beacon_data_ies()
 - Drop inapplicable change to WMM IE handling
 - Adjust filename]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/net/wireless/mwifiex/ie.c

index 3bf3d58bbc029b0a48a937a0c65d15a83552b295..69827b5f96b51a8d26df05a779fff8eab3148a7d 100644 (file)
@@ -328,6 +328,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
        struct ieee_types_header *rsn_ie, *wpa_ie = NULL;
        u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
        const u8 *vendor_ie;
+       unsigned int token_len;
+       int err = 0;
 
        if (info->tail && info->tail_len) {
                gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
@@ -341,8 +343,13 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
                rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN,
                                                  info->tail, info->tail_len);
                if (rsn_ie) {
-                       memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2);
-                       ie_len = rsn_ie->len + 2;
+                       token_len = rsn_ie->len + 2;
+                       if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       memcpy(gen_ie->ie_buffer + ie_len, rsn_ie, token_len);
+                       ie_len += token_len;
                        gen_ie->ie_length = cpu_to_le16(ie_len);
                }
 
@@ -352,9 +359,15 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
                                                    info->tail_len);
                if (vendor_ie) {
                        wpa_ie = (struct ieee_types_header *)vendor_ie;
-                       memcpy(gen_ie->ie_buffer + ie_len,
-                              wpa_ie, wpa_ie->len + 2);
-                       ie_len += wpa_ie->len + 2;
+                       token_len = wpa_ie->len + 2;
+                       if (token_len >
+                           info->tail + info->tail_len - (u8 *)wpa_ie ||
+                           ie_len + token_len > IEEE_MAX_IE_SIZE) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       memcpy(gen_ie->ie_buffer + ie_len, wpa_ie, token_len);
+                       ie_len += token_len;
                        gen_ie->ie_length = cpu_to_le16(ie_len);
                }
 
@@ -362,13 +375,16 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
                        if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx,
                                                         NULL, NULL,
                                                         NULL, NULL)) {
-                               kfree(gen_ie);
-                               return -1;
+                               err = -EINVAL;
+                               goto out;
                        }
                        priv->rsn_idx = rsn_idx;
                }
 
+       out:
                kfree(gen_ie);
+               if (err)
+                       return err;
        }
 
        return mwifiex_set_mgmt_beacon_data_ies(priv, info);