DivestOS/Patches/Linux_CVEs/CVE-2016-8465/3.18/2.patch
2017-10-29 22:14:37 -04:00

157 lines
4.8 KiB
Diff

From 4add5112babf94dbc0f86e93395b6622d5080d16 Mon Sep 17 00:00:00 2001
From: Insun Song <insun.song@broadcom.com>
Date: Thu, 3 Nov 2016 10:53:51 -0700
Subject: net: wireless: bcmdhd: fix buffer overrun in wl_cfgvendor_hotlist_cfg
fix buffer overrun found where user manipulated input parameters
1. allocate local buffer with max length than input sized.
2. length check added in each tlv parsing and added error handling.
3. limit max hotlist count to PFN_SW_MAX_NUM_APS(16).
bug=32474971
Signed-off-by: Insun Song <insun.song@broadcom.com>
Change-Id: I60d513a30875f6a8ee8cfdc557bdec1436416fe7
---
drivers/net/wireless/bcmdhd/wl_cfgvendor.c | 105 +++++++++++++++++++++--------
1 file changed, 77 insertions(+), 28 deletions(-)
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
index aa8f352..037e885 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
@@ -615,14 +615,22 @@ static int wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
gscan_hotlist_scan_params_t *hotlist_params;
int tmp, tmp1, tmp2, type, j = 0, dummy;
- const struct nlattr *outer, *inner, *iter;
+ const struct nlattr *outer, *inner = NULL, *iter;
uint8 flush = 0;
struct bssid_t *pbssid;
- hotlist_params = (gscan_hotlist_scan_params_t *)kzalloc(len, GFP_KERNEL);
+ if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
+ WL_ERR(("buffer length :%d wrong - bail out.\n", len));
+ return -EINVAL;
+ }
+
+ hotlist_params = kzalloc(sizeof(*hotlist_params)
+ + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)),
+ GFP_KERNEL);
+
if (!hotlist_params) {
WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len));
- return -1;
+ return -ENOMEM;
}
hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
@@ -630,37 +638,78 @@ static int wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
nla_for_each_attr(iter, data, len, tmp2) {
type = nla_type(iter);
switch (type) {
- case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
- pbssid = hotlist_params->bssid;
- nla_for_each_nested(outer, iter, tmp) {
- nla_for_each_nested(inner, outer, tmp1) {
- type = nla_type(inner);
+ case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
+ pbssid = hotlist_params->bssid;
+ nla_for_each_nested(outer, iter, tmp) {
+ nla_for_each_nested(inner, outer, tmp1) {
+ type = nla_type(inner);
- switch (type) {
- case GSCAN_ATTRIBUTE_BSSID:
- memcpy(&(pbssid[j].macaddr),
- nla_data(inner), ETHER_ADDR_LEN);
- break;
- case GSCAN_ATTRIBUTE_RSSI_LOW:
- pbssid[j].rssi_reporting_threshold =
- (int8) nla_get_u8(inner);
- break;
- case GSCAN_ATTRIBUTE_RSSI_HIGH:
- dummy = (int8) nla_get_u8(inner);
- break;
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BSSID:
+ if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
+ WL_DBG(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ memcpy(
+ &pbssid[j].macaddr,
+ nla_data(inner),
+ sizeof(pbssid[j].macaddr));
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_LOW:
+ if (nla_len(inner) != sizeof(uint8)) {
+ WL_DBG(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ pbssid[j].rssi_reporting_threshold =
+ (int8)nla_get_u8(inner);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_HIGH:
+ if (nla_len(inner) != sizeof(uint8)) {
+ WL_DBG(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
}
+ dummy = (int8)nla_get_u8(inner);
+ break;
}
- j++;
+ }
+ if (++j > PFN_SWC_MAX_NUM_APS) {
+ WL_DBG(("nbssid:%d exeed limit.\n",
+ hotlist_params->nbssid));
+ err = -EINVAL;
+ goto exit;
}
hotlist_params->nbssid = j;
- break;
- case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
- flush = nla_get_u8(iter);
- break;
- case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
- hotlist_params->lost_ap_window = nla_get_u32(iter);
- break;
}
+ break;
+ case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
+ if (nla_len(iter) != sizeof(uint8)) {
+ WL_DBG(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ flush = nla_get_u8(iter);
+ break;
+ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
+ if (nla_len(iter) != sizeof(uint32)) {
+ WL_DBG(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
+ break;
+ default:
+ WL_DBG(("Unknown type %d\n", type));
+ err = -EINVAL;
+ goto exit;
+ }
}
--
cgit v1.1