DivestOS/Patches/Linux_CVEs/CVE-2017-0790/ANY/0001.patch

174 lines
7.0 KiB
Diff
Raw Normal View History

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