OSDN Git Service

mwifiex: Fix possible buffer overflows in mwifiex_cmd_append_vsie_tlv()
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / net / wireless / mwifiex / scan.c
index c20017c..e7c8972 100644 (file)
@@ -151,7 +151,8 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
        if (((bss_desc->bcn_wpa_ie) &&
             ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id ==
              WLAN_EID_VENDOR_SPECIFIC))) {
-               iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
+               iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
+                                           WPA_GTK_OUI_OFFSET);
                oui = &mwifiex_wpa_oui[cipher][0];
                ret = mwifiex_search_oui_in_ie(iebody, oui);
                if (ret)
@@ -1219,6 +1220,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                }
                switch (element_id) {
                case WLAN_EID_SSID:
+                       if (element_len > IEEE80211_MAX_SSID_LEN)
+                               return -EINVAL;
                        bss_entry->ssid.ssid_len = element_len;
                        memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
                               element_len);
@@ -1228,6 +1231,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        break;
 
                case WLAN_EID_SUPP_RATES:
+                       if (element_len > MWIFIEX_SUPPORTED_RATES)
+                               return -EINVAL;
                        memcpy(bss_entry->data_rates, current_ptr + 2,
                               element_len);
                        memcpy(bss_entry->supported_rates, current_ptr + 2,
@@ -1237,6 +1242,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        break;
 
                case WLAN_EID_FH_PARAMS:
+                       if (element_len + 2 < sizeof(*fh_param_set))
+                               return -EINVAL;
                        fh_param_set =
                                (struct ieee_types_fh_param_set *) current_ptr;
                        memcpy(&bss_entry->phy_param_set.fh_param_set,
@@ -1245,6 +1252,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        break;
 
                case WLAN_EID_DS_PARAMS:
+                       if (element_len + 2 < sizeof(*ds_param_set))
+                               return -EINVAL;
                        ds_param_set =
                                (struct ieee_types_ds_param_set *) current_ptr;
 
@@ -1256,6 +1265,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        break;
 
                case WLAN_EID_CF_PARAMS:
+                       if (element_len + 2 < sizeof(*cf_param_set))
+                               return -EINVAL;
                        cf_param_set =
                                (struct ieee_types_cf_param_set *) current_ptr;
                        memcpy(&bss_entry->ss_param_set.cf_param_set,
@@ -1264,6 +1275,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        break;
 
                case WLAN_EID_IBSS_PARAMS:
+                       if (element_len + 2 < sizeof(*ibss_param_set))
+                               return -EINVAL;
                        ibss_param_set =
                                (struct ieee_types_ibss_param_set *)
                                current_ptr;
@@ -1273,10 +1286,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        break;
 
                case WLAN_EID_ERP_INFO:
+                       if (!element_len)
+                               return -EINVAL;
                        bss_entry->erp_flags = *(current_ptr + 2);
                        break;
 
                case WLAN_EID_PWR_CONSTRAINT:
+                       if (!element_len)
+                               return -EINVAL;
                        bss_entry->local_constraint = *(current_ptr + 2);
                        bss_entry->sensed_11h = true;
                        break;
@@ -1319,15 +1336,22 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                        vendor_ie = (struct ieee_types_vendor_specific *)
                                        current_ptr;
 
-                       if (!memcmp
-                           (vendor_ie->vend_hdr.oui, wpa_oui,
-                            sizeof(wpa_oui))) {
+                       /* 802.11 requires at least 3-byte OUI. */
+                       if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
+                               return -EINVAL;
+
+                       /* Not long enough for a match? Skip it. */
+                       if (element_len < sizeof(wpa_oui))
+                               break;
+
+                       if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
+                                   sizeof(wpa_oui))) {
                                bss_entry->bcn_wpa_ie =
                                        (struct ieee_types_vendor_specific *)
                                        current_ptr;
                                bss_entry->wpa_offset = (u16)
                                        (current_ptr - bss_entry->beacon_buf);
-                       } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+                       } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
                                    sizeof(wmm_oui))) {
                                if (total_ie_len ==
                                    sizeof(struct ieee_types_wmm_parameter) ||
@@ -1849,15 +1873,17 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
                                            ETH_ALEN))
                                        mwifiex_update_curr_bss_params(priv,
                                                                       bss);
-                               cfg80211_put_bss(priv->wdev.wiphy, bss);
-                       }
 
-                       if ((chan->flags & IEEE80211_CHAN_RADAR) ||
-                           (chan->flags & IEEE80211_CHAN_NO_IR)) {
-                               mwifiex_dbg(adapter, INFO,
-                                           "radar or passive channel %d\n",
-                                           channel);
-                               mwifiex_save_hidden_ssid_channels(priv, bss);
+                               if ((chan->flags & IEEE80211_CHAN_RADAR) ||
+                                   (chan->flags & IEEE80211_CHAN_NO_IR)) {
+                                       mwifiex_dbg(adapter, INFO,
+                                                   "radar or passive channel %d\n",
+                                                   channel);
+                                       mwifiex_save_hidden_ssid_channels(priv,
+                                                                         bss);
+                               }
+
+                               cfg80211_put_bss(priv->wdev.wiphy, bss);
                        }
                }
        } else {
@@ -2170,6 +2196,12 @@ mwifiex_update_chan_statistics(struct mwifiex_private *priv,
                                              sizeof(struct mwifiex_chan_stats);
 
        for (i = 0 ; i < num_chan; i++) {
+               if (adapter->survey_idx >= adapter->num_in_chan_stats) {
+                       mwifiex_dbg(adapter, WARN,
+                                   "FW reported too many channel results (max %d)\n",
+                                   adapter->num_in_chan_stats);
+                       return;
+               }
                chan_stats.chan_num = fw_chan_stats->chan_num;
                chan_stats.bandcfg = fw_chan_stats->bandcfg;
                chan_stats.flags = fw_chan_stats->flags;
@@ -2536,6 +2568,13 @@ mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
                        vs_param_set->header.len =
                                cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
                                & 0x00FF) + 2);
+                       if (le16_to_cpu(vs_param_set->header.len) >
+                               MWIFIEX_MAX_VSIE_LEN) {
+                               mwifiex_dbg(priv->adapter, ERROR,
+                                           "Invalid param length!\n");
+                               break;
+                       }
+
                        memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
                               le16_to_cpu(vs_param_set->header.len));
                        *buffer += le16_to_cpu(vs_param_set->header.len) +