diff options
author | Sudhir Kohalli <sudhir.kohalli@broadcom.com> | 2017-06-14 11:36:22 -0700 |
---|---|---|
committer | Jonathan Solnit <jsolnit@google.com> | 2017-07-19 17:57:10 +0000 |
commit | 01f610163f35e063204aa78bdfb8807823c27ff6 (patch) | |
tree | 0b045411628a5d67fe47370c094ea7b1503565c2 | |
parent | 32c61f97fa5a6c7b8d581b849d96e869e14b4342 (diff) | |
download | x86_64-01f610163f35e063204aa78bdfb8807823c27ff6.tar.gz |
net: wireless: bcmdhd: add boundary check in GSCAN full result handler
validtating each length fields before not to overflow allocated
data type. it prevent possiblity heap memory corrupted.
Signed-off-by: Sudhir Kohalli <sudhir.kohalli@broadcom.com>
Bug: 37357704
Change-Id: I7c04b93f3843c8100bd932fb9b7c67ef76b93050
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_linux.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_pno.c | 30 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_pno.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfg80211.c | 7 |
4 files changed, 37 insertions, 12 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 98aae6eb1715..7f88a5e1bca4 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -7666,11 +7666,12 @@ void * dhd_dev_hotlist_scan_event(struct net_device *dev, /* Linux wrapper to call common dhd_process_full_gscan_result */ void * dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, int *send_evt_bytes) +const void *data, uint32 len, int *send_evt_bytes) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_process_full_gscan_result(&dhd->pub, data, send_evt_bytes)); + return (dhd_process_full_gscan_result(&dhd->pub, data, len, + send_evt_bytes)); } void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c index 17656262837c..250898629170 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -3467,7 +3467,8 @@ void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) } void * -dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, + int *size) { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; @@ -3476,15 +3477,25 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) uint8 channel; uint32 mem_needed; struct timespec ts; + u32 bi_ie_length = 0; + u32 bi_ie_offset = 0; *size = 0; - gscan_result = (wl_gscan_result_t *)data; - if (!gscan_result) { DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } + + if ((len < sizeof(*gscan_result)) || + (len < dtoh32(gscan_result->buflen)) || + (dtoh32(gscan_result->buflen) > + (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { + DHD_ERROR(("%s: invalid gscan buflen:%u\n", __func__, + dtoh32(gscan_result->buflen))); + goto exit; + } + if (!gscan_result->bss_info) { DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); goto exit; @@ -3496,9 +3507,18 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size) DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } + + bi_ie_offset = dtoh32(bi->ie_offset); + bi_ie_length = dtoh32(bi->ie_length); + if ((bi_ie_offset + bi_ie_length) > bi_length) { + DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", + __func__, bi_ie_length, bi_ie_offset)); + goto exit; + } if (bi->SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len)); - bi->SSID_len = DOT11_MAX_SSID_LEN; + DHD_ERROR(("%s: Invalid SSID length %u\n", + __func__, bi->SSID_len)); + goto exit; } mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length; diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h index b1357f9e4e11..62efec428f2c 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd/dhd_pno.h @@ -444,7 +444,7 @@ int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes, hotlist_type_t type); void * dhd_dev_process_full_gscan_result(struct net_device *dev, - const void *data, int *send_evt_bytes); + const void *data, uint32 len, int *send_evt_bytes); extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); extern void dhd_dev_wait_batch_results_complete(struct net_device *dev); @@ -486,8 +486,9 @@ extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); extern void *dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes); extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes, hotlist_type_t type); -extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes); +extern void * +dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, + uint32 len, int *send_evt_bytes); extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); extern void dhd_wait_batch_results_complete(dhd_pub_t *dhd); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index eeee288a4ea7..baa94b8bc038 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -9114,10 +9114,13 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, } break; case WLC_E_PFN_GSCAN_FULL_RESULT: - ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes); + ptr = + dhd_dev_process_full_gscan_result(ndev, data, len, + &send_evt_bytes); if (ptr) { wl_cfgvendor_send_async_event(wiphy, ndev, - GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes); + GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, + send_evt_bytes); kfree(ptr); } break; |