mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
174 lines
7.0 KiB
Diff
174 lines
7.0 KiB
Diff
From 5575ff40a53a954ec942ff0c17b193433e72c132 Mon Sep 17 00:00:00 2001
|
|
From: Sudhir Kohalli <sudhir.kohalli@broadcom.com>
|
|
Date: Wed, 14 Jun 2017 11:36:22 -0700
|
|
Subject: 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
|
|
---
|
|
drivers/net/wireless/bcmdhd/dhd_linux.c | 5 +++--
|
|
drivers/net/wireless/bcmdhd/dhd_pno.c | 37 ++++++++++++++++++++++++-------
|
|
drivers/net/wireless/bcmdhd/dhd_pno.h | 7 +++---
|
|
drivers/net/wireless/bcmdhd/wl_cfg80211.c | 7 ++++--
|
|
4 files changed, 41 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
|
|
index 0b66e91..abc4331 100644
|
|
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
|
|
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
|
|
@@ -8420,11 +8420,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 c80adec..3103f89 100644
|
|
--- a/drivers/net/wireless/bcmdhd/dhd_pno.c
|
|
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.c
|
|
@@ -47,6 +47,7 @@
|
|
#ifdef GSCAN_SUPPORT
|
|
#include <linux/gcd.h>
|
|
#endif /* GSCAN_SUPPORT */
|
|
+#include <wl_cfg80211.h>
|
|
|
|
#ifdef __BIG_ENDIAN
|
|
#include <bcmendian.h>
|
|
@@ -3693,7 +3694,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;
|
|
@@ -3702,15 +3704,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;
|
|
@@ -3722,12 +3734,21 @@ 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_full_result_t, ie_data) + bi->ie_length;
|
|
+ mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi_ie_length;
|
|
result = (wifi_gscan_full_result_t *) kmalloc(mem_needed, GFP_KERNEL);
|
|
|
|
if (!result) {
|
|
@@ -3749,9 +3770,9 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, int *size)
|
|
result->fixed.ts = (uint64) TIMESPEC_TO_US(ts);
|
|
result->fixed.beacon_period = dtoh16(bi->beacon_period);
|
|
result->fixed.capability = dtoh16(bi->capability);
|
|
- result->ie_length = dtoh32(bi->ie_length);
|
|
+ result->ie_length = bi_ie_length;
|
|
memcpy(&result->fixed.macaddr, &bi->BSSID, ETHER_ADDR_LEN);
|
|
- memcpy(result->ie_data, ((uint8 *)bi + bi->ie_offset), bi->ie_length);
|
|
+ memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length);
|
|
*size = mem_needed;
|
|
exit:
|
|
return result;
|
|
diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h
|
|
index a0edf54..3398752 100644
|
|
--- a/drivers/net/wireless/bcmdhd/dhd_pno.h
|
|
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.h
|
|
@@ -512,7 +512,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 int dhd_dev_wait_batch_results_complete(struct net_device *dev);
|
|
@@ -563,8 +563,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 int 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 d8c748d..1d1e2a8 100644
|
|
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
|
|
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
|
|
@@ -9452,10 +9452,13 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
|
|
err = -EINVAL;
|
|
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);
|
|
} else
|
|
err = -ENOMEM;
|
|
--
|
|
cgit v1.1
|
|
|