diff options
author | Sungjoon Park <sungjoon.park@broadcom.corp-partner.google.com> | 2022-12-12 16:00:50 +0900 |
---|---|---|
committer | Necip Fazil Yildiran <necip@google.com> | 2022-12-21 22:02:35 +0000 |
commit | 2e569679e6615b5d4779d7240cd17142d1cc4e48 (patch) | |
tree | 092dc715d226c288f191c42349e1021c9268c7af | |
parent | 8cc1f86557efc967273cbe8a9da1d09440ad30e2 (diff) | |
download | drivers-2e569679e6615b5d4779d7240cd17142d1cc4e48.tar.gz |
bcmdhd: Fixed Memory OOB Read/Write in function wl_update_hidden_ap_ie
In wl_update_hidden_ap_ie of wl_cfgscan.c, there is a possible out of bounds write due to a missing bounds check.
Fix:
1. Added bounds check.
2. If the ie_offset + ie_length is not matched with length then bi might be corrupted.
Ignoring that AP bi update.
Bug: 254029309
Test: BRCM Internal test is finished without regression.
Change-Id: Ibd638e27a09f657f903c46e8c4712732af47cfc9
Signed-off-by: Sungjoon Park <sungjoon.park@broadcom.corp-partner.google.com>
(cherry picked from commit 31b7bb4d289272bdcde29b8e37cc2a5c2d5e2760)
Signed-off-by: Necip Fazil Yildiran <necip@google.com>
-rw-r--r-- | net/wireless/bcmdhd/wl_cfgscan.c | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/net/wireless/bcmdhd/wl_cfgscan.c b/net/wireless/bcmdhd/wl_cfgscan.c index 3f37fd4..1fae1e7 100644 --- a/net/wireless/bcmdhd/wl_cfgscan.c +++ b/net/wireless/bcmdhd/wl_cfgscan.c @@ -196,6 +196,7 @@ static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 * int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN); int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len; /* cfg80211_find_ie defined in kernel returning const u8 */ + int ret = 0; GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size); @@ -237,10 +238,19 @@ static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 * */ if ((update_ssid && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) { WL_INFORM_MEM(("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); + ret = memmove_s(ssidie + ssid_len + 2, available_buffer_len, + (ssidie + 2) + ssidie[1], remaining_ie_buf_len); + if (ret) { + WL_ERR(("SSID Info memmove failed:%d, destsz:%d, n:%d\n", + ret, available_buffer_len, remaining_ie_buf_len)); + return; + } + ret = memcpy_s(ssidie + 2, DOT11_MAX_SSID_LEN, bi->SSID, ssid_len); + if (ret) { + WL_ERR(("SSID Info memcpy failed:%d, destsz:%d, n:%d\n", + ret, DOT11_MAX_SSID_LEN, ssid_len)); + return; + } *ie_size = *ie_size + ssid_len - ssidie[1]; ssidie[1] = ssid_len; } else if (ssid_len < ssidie[1]) { @@ -249,8 +259,14 @@ static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 * } return; } - if (*(ssidie + 2) == '\0') - memcpy(ssidie + 2, bi->SSID, ssid_len); + if (*(ssidie + 2) == '\0') { + ret = memcpy_s(ssidie + 2, DOT11_MAX_SSID_LEN, bi->SSID, ssid_len); + if (ret) { + WL_ERR(("memcopy failed:%d, destsz:%d, n:%d\n", + ret, DOT11_MAX_SSID_LEN, ssid_len)); + return; + } + } return; } @@ -258,12 +274,19 @@ static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size) { struct wl_ie *ie = wl_to_ie(cfg); s32 err = 0; + int ret = 0; if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { WL_ERR(("ei_stream crosses buffer boundary\n")); return -ENOSPC; } - memcpy(&ie->buf[ie->offset], ie_stream, ie_size); + ret = memcpy_s(&ie->buf[ie->offset], (sizeof(ie->buf) - ie->offset), + ie_stream, ie_size); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz: %lu, n: %d\n", + ret, (sizeof(ie->buf) - ie->offset), ie_size)); + return BCME_ERROR; + } ie->offset += ie_size; return err; @@ -316,6 +339,12 @@ s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool updat return err; } + if (bi->length < (bi->ie_offset + bi->ie_length)) { + WL_ERR(("IE length is not Valid. IE offse:%d, len:%d\n", + bi->ie_offset, bi->ie_length)); + return -EINVAL; + } + if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) { WL_ERR(("wrong SSID len:%d\n", bi->SSID_len)); return -EINVAL; @@ -626,6 +655,7 @@ wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, struct wiphy *wiphy = NULL; wl_bcnrecv_result_t *bcn_recv = NULL; struct timespec ts; + int ret = 0; if (!bi) { WL_ERR(("%s: bi is NULL\n", __func__)); err = BCME_NORESOURCE; @@ -648,11 +678,15 @@ wl_bcnrecv_result_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_ERR(("Failed to allocate memory\n")); return -ENOMEM; } - /* Returning void here as copy size does not exceed dest size of SSID */ - (void)memcpy_s((char *)bcn_recv->SSID, DOT11_MAX_SSID_LEN, - (char *)bi->SSID, DOT11_MAX_SSID_LEN); - /* Returning void here as copy size does not exceed dest size of ETH_LEN */ - (void)memcpy_s(&bcn_recv->BSSID, ETHER_ADDR_LEN, &bi->BSSID, ETH_ALEN); + ret = memcpy_s((char *)bcn_recv->SSID, sizeof(bcn_recv->SSID), + (char *)bi->SSID, bi->SSID_len); + if (ret) { + WL_ERR(("memcpy failed:%d, destsz:%lu, n:%d\n", + ret, sizeof(bcn_recv->SSID), bi->SSID_len)); + err = BCME_ERROR; + goto exit; + } + eacopy(&bi->BSSID, &bcn_recv->BSSID); bcn_recv->channel = wf_chspec_ctlchan( wl_chspec_driver_to_host(bi->chanspec)); bcn_recv->beacon_interval = bi->beacon_period; |