DivestOS/Patches/Linux_CVEs/CVE-2016-8456/ANY/0001.patch
2017-11-07 17:32:46 -05:00

349 lines
12 KiB
Diff

From e5c1b001a822e8b38680655c400e7b3f67cc3323 Mon Sep 17 00:00:00 2001
From: Insun Song <insun.song@broadcom.com>
Date: Thu, 10 Nov 2016 15:01:31 -0800
Subject: [PATCH] net: wireless: bcmdhd: fix buffer overrun in anqpo config
1. memory leak fix when input packet content corrupted.
2. reduced unnecessary debug messages
Signed-off-by: Insun Song <insun.song@broadcom.com>
Bug: 32219453
Change-Id: I0f79310c97571cd46afff29f58f66b17a2471927
---
drivers/net/wireless/bcmdhd/dhd_linux.c | 2 +
drivers/net/wireless/bcmdhd/dhd_pno.c | 3 +-
drivers/net/wireless/bcmdhd/dhd_pno.h | 17 ++--
drivers/net/wireless/bcmdhd/wl_cfg80211.c | 14 +++
drivers/net/wireless/bcmdhd/wl_cfgvendor.c | 141 ++++++++++++++++++++---------
5 files changed, 127 insertions(+), 50 deletions(-)
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 2fd2934a7e851..00201de5de5b8 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -8621,6 +8621,7 @@ int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid
return err;
}
+#ifdef DHD_ANQPO_SUPPORT
void * dhd_dev_process_anqpo_result(struct net_device *dev,
const void *data, uint32 event, int *send_evt_bytes)
{
@@ -8628,6 +8629,7 @@ void * dhd_dev_process_anqpo_result(struct net_device *dev,
return (dhd_pno_process_anqpo_result(&dhd->pub, data, event, send_evt_bytes));
}
+#endif /* DHD_ANQPO_SUPPORT */
#endif /* GSCAN_SUPPORT */
int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start,
diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c
index 8d6d234cd11b3..a88d1e2e41320 100644
--- a/drivers/net/wireless/bcmdhd/dhd_pno.c
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.c
@@ -3798,6 +3798,7 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int
return results;
}
+#ifdef DHD_ANQPO_SUPPORT
void *
dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size)
{
@@ -3849,7 +3850,7 @@ dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int
return result;
}
-
+#endif /* DHD_ANQPO_SUPPORT */
void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes,
hotlist_type_t type)
diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h
index b61d0fd866364..a0edf54049acf 100644
--- a/drivers/net/wireless/bcmdhd/dhd_pno.h
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.h
@@ -98,8 +98,9 @@
#define CHANNEL_BUCKET_EMPTY_INDEX 0xFFFF
#define GSCAN_RETRY_THRESHOLD 3
-#define MAX_EPNO_SSID_NUM 64
-
+#define MAX_EPNO_SSID_NUM 64
+#define GSCAN_ANQPO_MAX_HS_LIST_SIZE 16
+#define ANQPO_MAX_HS_NAI_REALM_SIZE 256
#endif /* GSCAN_SUPPORT */
enum scan_status {
@@ -351,10 +352,10 @@ typedef struct gscan_results_cache {
} gscan_results_cache_t;
typedef struct {
- int id; /* identifier of this network block, report this in event */
- char realm[256]; /* null terminated UTF8 encoded realm, 0 if unspecified */
- int64_t roamingConsortiumIds[16]; /* roaming consortium ids to match, 0s if unspecified */
- uint8 plmn[3]; /* mcc/mnc combination as per rules, 0s if unspecified */
+ int id;
+ char realm[ANQPO_MAX_HS_NAI_REALM_SIZE];
+ int64_t roamingConsortiumIds[ANQPO_MAX_PFN_HS];
+ uint8 plmn[ANQPO_MCC_LENGTH];
} wifi_passpoint_network;
typedef struct dhd_pno_gscan_capabilities {
@@ -517,8 +518,10 @@ extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_
extern int dhd_dev_wait_batch_results_complete(struct net_device *dev);
extern void * dhd_dev_process_epno_result(struct net_device *dev,
const void *data, uint32 event, int *send_evt_bytes);
+#ifdef DHD_ANQPO_SUPPORT
extern void * dhd_dev_process_anqpo_result(struct net_device *dev,
const void *data, uint32 event, int *send_evt_bytes);
+#endif /* DHD_ANQPO_SUPPORT */
extern int dhd_dev_set_epno(struct net_device *dev);
extern int dhd_dev_flush_fw_epno(struct net_device *dev);
#endif /* GSCAN_SUPPORT */
@@ -567,7 +570,9 @@ 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);
extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data,
uint32 event, int *size);
+#ifdef DHD_ANQPO_SUPPORT
extern void * dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size);
+#endif /* DHD_ANQPO_SUPPORT */
extern void dhd_pno_translate_epno_fw_flags(uint32 *flags);
extern int dhd_pno_set_epno(dhd_pub_t *dhd);
extern int dhd_pno_flush_fw_epno(dhd_pub_t *dhd);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index a56ba6b82e197..3d70a82adfa5e 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -9423,6 +9423,16 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
} else
err = -ENOMEM;
break;
+ case WLC_E_PFN_SSID_EXT:
+ ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
+ if (ptr) {
+ wl_cfgvendor_send_async_event(wiphy, ndev,
+ GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
+ kfree(ptr);
+ } else
+ err = -ENOMEM;
+ break;
+#ifdef DHD_ANQPO_SUPPORT
case WLC_E_PFN_NET_FOUND:
ptr = dhd_dev_process_anqpo_result(ndev, data, event, &len);
if (ptr) {
@@ -9432,6 +9442,7 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
} else
err = -ENOMEM;
break;
+#endif /* DHD_ANQPO_SUPPORT */
default:
WL_ERR(("Unknown event %d\n", event));
break;
@@ -10035,7 +10046,10 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
+ cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
+#ifdef DHD_ANQPO_SUPPORT
cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
+#endif /* DHD_ANQPO_SUPPORT */
cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
#endif /* GSCAN_SUPPORT */
cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
index 5be16a72aa43f..b156660ed053a 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
@@ -939,10 +939,13 @@ static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
return err;
}
+#ifdef DHD_ANQPO_SUPPORT
static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy,
struct wireless_dev *wdev, const void *data, int len)
{
- int err = BCME_ERROR, rem, type, hs_list_size = 0, malloc_size, i = 0, j, k, num_oi, oi_len;
+ int err = BCME_ERROR, rem, type, malloc_size, i = 0;
+ uint32 hs_list_size = 0;
+ int j, k, num_oi, oi_len;
wifi_passpoint_network *hs_list = NULL, *src_hs;
wl_anqpo_pfn_hs_list_t *anqpo_hs_list;
wl_anqpo_pfn_hs_t *dst_hs;
@@ -953,52 +956,100 @@ static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy,
char *rcid;
nla_for_each_attr(iter, data, len, rem) {
- type = nla_type(iter);
- switch (type) {
- case GSCAN_ATTRIBUTE_ANQPO_HS_LIST:
- if (hs_list_size > 0) {
- hs_list = kmalloc(hs_list_size*sizeof(wifi_passpoint_network), GFP_KERNEL);
- if (hs_list == NULL) {
- WL_ERR(("failed to allocate hs_list\n"));
- return -ENOMEM;
- }
- }
- nla_for_each_nested(outer, iter, tmp) {
- nla_for_each_nested(inner, outer, tmp1) {
- type = nla_type(inner);
+ type = nla_type(iter);
+ switch (type) {
+ case GSCAN_ATTRIBUTE_ANQPO_HS_LIST:
+ if (hs_list) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (hs_list_size > 0) {
+ hs_list = kzalloc(hs_list_size *
+ sizeof(wifi_passpoint_network), GFP_KERNEL);
+ if (!hs_list) {
+ WL_ERR(("failed to allocate hs_list\n"));
+ return -ENOMEM;
+ }
+ }
+ nla_for_each_nested(outer, iter, tmp) {
+ if (i == hs_list_size)
+ break;
+ nla_for_each_nested(inner, outer, tmp1) {
+ type = nla_type(inner);
- switch (type) {
- case GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID:
- hs_list[i].id = nla_get_u32(inner);
- WL_ERR(("%s: net id: %d\n", __func__, hs_list[i].id));
- break;
- case GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM:
- memcpy(hs_list[i].realm,
- nla_data(inner), 256);
- WL_ERR(("%s: realm: %s\n", __func__, hs_list[i].realm));
- break;
- case GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID:
- memcpy(hs_list[i].roamingConsortiumIds,
- nla_data(inner), 128);
- break;
- case GSCAN_ATTRIBUTE_ANQPO_HS_PLMN:
- memcpy(hs_list[i].plmn,
- nla_data(inner), 3);
- WL_ERR(("%s: plmn: %c %c %c\n", __func__, hs_list[i].plmn[0], hs_list[i].plmn[1], hs_list[i].plmn[2]));
- break;
- }
- }
- i++;
+ switch (type) {
+ case GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID:
+ if (nla_len(inner) != sizeof(hs_list[i].id)) {
+ err = -EINVAL;
+ goto exit;
}
+ hs_list[i].id = nla_get_u32(inner);
+ WL_DBG(("%s: net id: %d\n",
+ __func__, hs_list[i].id));
break;
- case GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE:
- hs_list_size = nla_get_u32(iter);
- WL_ERR(("%s: ANQPO: %d\n", __func__, hs_list_size));
+ case GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM:
+ if (nla_len(inner) !=
+ sizeof(hs_list[i].realm)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ memcpy(hs_list[i].realm, nla_data(inner),
+ sizeof(hs_list[i].realm));
+ WL_DBG(("%s: realm: %s\n",
+ __func__, hs_list[i].realm));
break;
- default:
- WL_ERR(("Unknown type: %d\n", type));
- return err;
+ case GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID:
+ if (nla_len(inner) != sizeof(hs_list[i].
+ roamingConsortiumIds)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ memcpy(hs_list[i].roamingConsortiumIds,
+ nla_data(inner),
+ sizeof(hs_list[i].roamingConsortiumIds));
+ break;
+ case GSCAN_ATTRIBUTE_ANQPO_HS_PLMN:
+ if (nla_len(inner) != sizeof(hs_list[i].plmn)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ memcpy(hs_list[i].plmn,
+ nla_data(inner),
+ sizeof(hs_list[i].plmn));
+ WL_DBG(("%s: plmn: %c %c %c\n",
+ __func__, hs_list[i].plmn[0],
+ hs_list[i].plmn[1],
+ hs_list[i].plmn[2]));
+ break;
+ }
+ }
+ i++;
}
+ break;
+ case GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE:
+ if (nla_len(iter) != sizeof(hs_list_size)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ hs_list_size = nla_get_u32(iter);
+ if ((hs_list_size == 0) ||
+ (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE)) {
+ WL_ERR(("%s: ANQPO: %d\n", __func__, hs_list_size));
+ err = -EINVAL;
+ goto exit;
+ }
+ WL_DBG(("%s: ANQPO: %d\n", __func__, hs_list_size));
+ break;
+ default:
+ WL_ERR(("Unknown type: %d\n", type));
+ err = -EINVAL;
+ goto exit;
+ }
+
}
malloc_size = OFFSETOF(wl_anqpo_pfn_hs_list_t, hs) +
@@ -1046,7 +1097,7 @@ static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy,
kfree(hs_list);
return err;
}
-
+#endif /* DHD_ANQPO_SUPPORT */
static int wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
struct wireless_dev *wdev, const void *data, int len)
{
@@ -3065,6 +3116,7 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = {
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = wl_cfgvendor_set_bssid_blacklist
},
+#ifdef DHD_ANQPO_SUPPORT
{
{
.vendor_id = OUI_GOOGLE,
@@ -3073,6 +3125,7 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = {
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = wl_cfgvendor_gscan_anqpo_config
},
+#endif /* DHD_ANQPO_SUPPORT */
#endif /* GSCAN_SUPPORT */
{
{
@@ -3233,7 +3286,9 @@ static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
{ OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
{ OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
{ OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
+#ifdef DHD_ANQPO_SUPPORT
{ OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
+#endif /* DHD_ANQPO_SUPPORT */
{ OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
{ OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }
};