summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudhir Kohalli <sudhir.kohalli@broadcom.com>2017-06-14 11:36:22 -0700
committerJonathan Solnit <jsolnit@google.com>2017-07-19 17:57:10 +0000
commit01f610163f35e063204aa78bdfb8807823c27ff6 (patch)
tree0b045411628a5d67fe47370c094ea7b1503565c2
parent32c61f97fa5a6c7b8d581b849d96e869e14b4342 (diff)
downloadx86_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.c5
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pno.c30
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pno.h7
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c7
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;