From 8a1269e6d9730328cf1c2784024a5accca6ae633 Mon Sep 17 00:00:00 2001 From: Jerry Lee <jerrylee@broadcom.com> Date: Wed, 30 Mar 2016 18:01:31 -0700 Subject: [PATCH] net: wireless: bcmdhd: Verify SSID length Ensure SSID length is correct before memcpy Bug=26571522 Bug=27240072 Signed-off-by: Jerry Lee <jerrylee@broadcom.com> --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 88 +++++++++++++++-------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 15f15d555df2..51e2c2774bd5 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -1815,15 +1815,17 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req WL_SCAN(("Scanning all channels\n")); } n_channels = j; + /* Copy ssid array if applicable */ WL_SCAN(("### List of SSIDs to scan ###\n")); if (n_ssids > 0) { offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); offset = roundup(offset, sizeof(u32)); 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)); @@ -2716,10 +2718,12 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, WL_TRACE(("In\n")); RETURN_EIO_IF_NOT_UP(wl); WL_INFO(("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; } + if (wl_get_drv_status(wl, CONNECTED, dev)) { struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(wl, dev, WL_PROF_SSID); u8 *bssid = (u8 *)wl_read_prof(wl, dev, WL_PROF_BSSID); @@ -5730,17 +5734,16 @@ static s32 wl_cfg80211_bcn_set_params( } } - if ((info->ssid) && (info->ssid_len > 0) && - (info->ssid_len <= 32)) { + if ((info->ssid) && (info->ssid_len > 0) && (info->ssid_len <= DOT11_MAX_SSID_LEN)) { WL_DBG(("SSID (%s) len:%d \n", info->ssid, info->ssid_len)); if (dev_role == NL80211_IFTYPE_AP) { /* Store the hostapd SSID */ - memset(wl->hostapd_ssid.SSID, 0x00, 32); + memset(wl->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); memcpy(wl->hostapd_ssid.SSID, info->ssid, info->ssid_len); wl->hostapd_ssid.SSID_len = info->ssid_len; } else { - /* P2P GO */ - memset(wl->p2p->ssid.SSID, 0x00, 32); + /* P2P GO */ + memset(wl->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN); memcpy(wl->p2p->ssid.SSID, info->ssid, info->ssid_len); wl->p2p->ssid.SSID_len = info->ssid_len; } @@ -5870,11 +5873,13 @@ wl_cfg80211_bcn_bringup_ap( } memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ join_params_size = sizeof(join_params.ssid); - memcpy(join_params.ssid.SSID, wl->hostapd_ssid.SSID, - wl->hostapd_ssid.SSID_len); - join_params.ssid.SSID_len = htod32(wl->hostapd_ssid.SSID_len); + join_params.ssid.SSID_len = MIN(wl->hostapd_ssid.SSID_len, + (uint32)DOT11_MAX_SSID_LEN); + memcpy(join_params.ssid.SSID, wl->hostapd_ssid.SSID, 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, @@ -6381,20 +6386,22 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, goto fail; ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + /* find the SSID */ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], info->head_len - ie_offset, DOT11_MNG_SSID_ID)) != NULL) { if (dev_role == NL80211_IFTYPE_AP) { /* Store the hostapd SSID */ - memset(&wl->hostapd_ssid.SSID[0], 0x00, 32); - memcpy(&wl->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len); - wl->hostapd_ssid.SSID_len = ssid_ie->len; + memset(&wl->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); + wl->hostapd_ssid.SSID_len = MIN((int)ssid_ie->len, DOT11_MAX_SSID_LEN); + memcpy(&wl->hostapd_ssid.SSID[0], ssid_ie->data, + wl->hostapd_ssid.SSID_len); } else { - /* P2P GO */ - memset(&wl->p2p->ssid.SSID[0], 0x00, 32); - memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len); - wl->p2p->ssid.SSID_len = ssid_ie->len; + /* P2P GO */ + memset(&wl->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN); + wl->p2p->ssid.SSID_len = MIN((int)ssid_ie->len, DOT11_MAX_SSID_LEN); + memcpy(wl->p2p->ssid.SSID, ssid_ie->data, wl->p2p->ssid.SSID_len); } } @@ -6530,8 +6537,11 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy, ssid = &request->match_sets[i].ssid; /* No need to include null ssid */ if (ssid->ssid_len) { - memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, ssid->ssid_len); - ssids_local[ssid_cnt].SSID_len = ssid->ssid_len; + ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len, + (uint8)DOT11_MAX_SSID_LEN); + memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, + ssids_local[ssid_cnt].SSID_len); + if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) { ssids_local[ssid_cnt].hidden = TRUE; WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid)); @@ -10634,10 +10644,9 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev, switch (item) { case WL_PROF_SSID: 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; + memset(profile->ssid.SSID, 0, sizeof(profile->ssid.SSID)); + 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) @@ -10720,23 +10729,44 @@ static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size) { 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); + + /* + * 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; - if (ssidie[1] != bi->SSID_len) { + + 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] != ssid_len) { if (ssidie[1]) { WL_ERR(("%s: Wrong SSID len: %d != %d\n", __FUNCTION__, ssidie[1], bi->SSID_len)); return; } - memmove(ssidie + bi->SSID_len + 2, ssidie + 2, *ie_size - (ssidie + 2 - ie_stream)); - memcpy(ssidie + 2, bi->SSID, bi->SSID_len); - *ie_size = *ie_size + bi->SSID_len; - ssidie[1] = bi->SSID_len; + + WL_ERR(("Changing the SSID Info.\n")); + memmove(ssidie + ssid_len + 2, + (ssidie + 2) + ssidie[1], 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; } -- GitLab