net: wireless: bcmdhd_88: Verify SSID length
[linux-3.10.git] / drivers / net / wireless / bcmdhd / wl_cfg80211.c
index ff584b4..eae4a41 100755 (executable)
@@ -2208,7 +2208,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
                ptr = (char*)params + offset;
                for (i = 0; i < n_ssids; i++) {
                        memset(&ssid, 0, sizeof(wlc_ssid_t));
-                       ssid.SSID_len = request->ssids[i].ssid_len;
+                       ssid.SSID_len = MIN((int)request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN);
                        memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
                        if (!ssid.SSID_len)
                                WL_SCAN(("%d: Broadcast scan\n", i));
@@ -3533,7 +3533,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
        WL_TRACE(("In\n"));
        RETURN_EIO_IF_NOT_UP(cfg);
        WL_INFORM(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
-       if (!params->ssid || params->ssid_len <= 0) {
+       if (!params->ssid || params->ssid_len <= 0 ||
+               params->ssid_len >  DOT11_MAX_SSID_LEN) {
                WL_ERR(("Invalid parameter\n"));
                return -EINVAL;
        }
@@ -7012,16 +7013,16 @@ static s32 wl_cfg80211_bcn_set_params(
        }
 
        if ((info->ssid) && (info->ssid_len > 0) &&
-               (info->ssid_len <= 32)) {
+               (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
                WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
                if (dev_role == NL80211_IFTYPE_AP) {
                        /* Store the hostapd SSID */
-                       memset(cfg->hostapd_ssid.SSID, 0x00, 32);
+                       memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
                        memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
                        cfg->hostapd_ssid.SSID_len = info->ssid_len;
                } else {
                                /* P2P GO */
-                       memset(cfg->p2p->ssid.SSID, 0x00, 32);
+                       memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
                        memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
                        cfg->p2p->ssid.SSID_len = info->ssid_len;
                }
@@ -7153,9 +7154,11 @@ wl_cfg80211_bcn_bringup_ap(
                memset(&join_params, 0, sizeof(join_params));
                /* join parameters starts with ssid */
                join_params_size = sizeof(join_params.ssid);
+               join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
+                       (uint32)DOT11_MAX_SSID_LEN);
                memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
-                       cfg->hostapd_ssid.SSID_len);
-               join_params.ssid.SSID_len = htod32(cfg->hostapd_ssid.SSID_len);
+                       join_params.ssid.SSID_len);
+               join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
 
                /* create softap */
                if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
@@ -7777,14 +7780,16 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                DOT11_MNG_SSID_ID)) != NULL) {
                if (dev_role == NL80211_IFTYPE_AP) {
                        /* Store the hostapd SSID */
-                       memset(&cfg->hostapd_ssid.SSID[0], 0x00, 32);
-                       memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len);
-                       cfg->hostapd_ssid.SSID_len = ssid_ie->len;
+                       memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+                       cfg->hostapd_ssid.SSID_len = MIN((int)ssid_ie->len, DOT11_MAX_SSID_LEN);
+                       memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
+                               cfg->hostapd_ssid.SSID_len);
                } else {
                                /* P2P GO */
-                       memset(&cfg->p2p->ssid.SSID[0], 0x00, 32);
-                       memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len);
-                       cfg->p2p->ssid.SSID_len = ssid_ie->len;
+                       memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+                       cfg->p2p->ssid.SSID_len = MIN((int)ssid_ie->len, DOT11_MAX_SSID_LEN);
+                       memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
+                               cfg->p2p->ssid.SSID_len);
                }
        }
 
@@ -7922,8 +7927,10 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
        if (request->n_match_sets > 0) {
                for (i = 0; i < request->n_match_sets; i++) {
                        ssid = &request->match_sets[i].ssid;
-                       memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len);
-                       ssids_local[i].SSID_len = ssid->ssid_len;
+                       ssids_local[i].SSID_len = MIN(ssid->ssid_len,
+                               (uint32)DOT11_MAX_SSID_LEN);
+                       memcpy(ssids_local[i].SSID, ssid->ssid,
+                               ssids_local[i].SSID_len);
                        WL_PNO((">>> PNO filter set for ssid (%s) \n", ssid->ssid));
                        ssid_count++;
                }
@@ -12881,8 +12888,8 @@ wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                ssid = (wlc_ssid_t *) data;
                memset(profile->ssid.SSID, 0,
                        sizeof(profile->ssid.SSID));
-               memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
-               profile->ssid.SSID_len = ssid->SSID_len;
+               profile->ssid.SSID_len = MIN(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
+               memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
                break;
        case WL_PROF_BSSID:
                if (data)
@@ -12965,27 +12972,43 @@ static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
 static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam)
 {
        u8 *ssidie;
+       int32 ssid_len = MIN((int)bi->SSID_len, DOT11_MAX_SSID_LEN);
+       int32 remaining_ie_buf_len, available_buffer_len;
        ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
-       if (!ssidie)
+       /* ERROR out if
+        * 1. No ssid IE is FOUND or
+        * 2. New ssid length is > what was allocated for existing ssid (as
+        * we do not want to overwrite the rest of the IEs) or
+        * 3. If in case of erroneous buffer input where ssid length doesnt match the space
+        * allocated to it.
+        */
+       if (!ssidie) {
+               return;
+       }
+       available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
+       remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
+       if ((ssid_len > ssidie[1]) ||
+               (ssidie[1] > available_buffer_len)) {
                return;
-       if (ssidie[1] != bi->SSID_len) {
+       }
+       if (ssidie[1] != ssid_len) {
                if (ssidie[1]) {
                        WL_ERR(("%s: Wrong SSID len: %d != %d\n",
                                __FUNCTION__, ssidie[1], bi->SSID_len));
                }
                if (roam) {
                        WL_ERR(("Changing the SSID Info.\n"));
-                       memmove(ssidie + bi->SSID_len + 2,
+                       memmove(ssidie + ssid_len + 2,
                                (ssidie + 2) + ssidie[1],
-                               *ie_size - (ssidie + 2 + ssidie[1] - ie_stream));
-                       memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
-                       *ie_size = *ie_size + bi->SSID_len - ssidie[1];
-                       ssidie[1] = bi->SSID_len;
+                               remaining_ie_buf_len);
+                       memcpy(ssidie + 2, bi->SSID, ssid_len);
+                       *ie_size = *ie_size + ssid_len - ssidie[1];
+                       ssidie[1] = ssid_len;
                }
                return;
        }
        if (*(ssidie + 2) == '\0')
-                memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
+                memcpy(ssidie + 2, bi->SSID, ssid_len);
        return;
 }