diff options
author | Patrick Tjin <pattjin@google.com> | 2015-12-09 21:17:56 -0800 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2016-03-10 13:13:39 -0800 |
commit | a42d665a3c05e23df0f2700abdc801e7b136a67a (patch) | |
tree | 95f9531542c48e407ce6ea2f2560ec3a93f9d192 | |
parent | 9f6c596b5e4402a8d74606f18138bf8b9aae0cea (diff) | |
download | v4.1-a42d665a3c05e23df0f2700abdc801e7b136a67a.tar.gz |
net: wireless: bcmdhd: check packet length for event messages
Check the datalen field is less than the size of
packet received from the network.
Signed-off-by: Patrick Tjin <pattjin@google.com>
Bug: 27335472
[fixes CVE-2016-0802]
Signed-off-by: Kees Cook <keescook@chromium.org>
Change-Id: I92b394e85cfc61a0e08fb5bc573a4c000e027fad
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_common.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_linux.c | 9 |
3 files changed, 17 insertions, 6 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index d0dd1ac08ba..fbc6269a759 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -1066,7 +1066,7 @@ extern int net_os_send_hang_message(struct net_device *dev); extern int net_os_send_hang_message_reason(struct net_device *dev, const char *string_num); extern bool dhd_wowl_cap(void *bus); -extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, +extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, size_t pktlen, wl_event_msg_t *, void **data_ptr, void *); extern void wl_event_to_host_order(wl_event_msg_t * evt); extern int wl_host_event_get_data(void *pktdata, wl_event_msg_t *event, void **data_ptr); diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 9955e90c6dd..55bc9ebc992 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -2264,7 +2264,7 @@ wl_host_event_get_data(void *pktdata, wl_event_msg_t *event, void **data_ptr) } int -wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, +wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t pktlen, wl_event_msg_t *event, void **data_ptr, void *raw_event) { bcm_event_t *pvt_data; @@ -2279,14 +2279,24 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, return ret; } + if (pktlen < sizeof(bcm_event_t)) + return (BCME_ERROR); + pvt_data = (bcm_event_t *)pktdata; event_data = *data_ptr; type = ntoh32_ua((void *)&event->event_type); flags = ntoh16_ua((void *)&event->flags); status = ntoh32_ua((void *)&event->status); + datalen = ntoh32_ua((void *)&event->datalen); + if (datalen > pktlen) + return (BCME_ERROR); + evlen = datalen + sizeof(bcm_event_t); + if (evlen > pktlen) { + return (BCME_ERROR); + } switch (type) { #ifdef PROP_TXSTATUS diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 0cd833b3589..495a0b80c1e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1383,7 +1383,7 @@ static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); #endif /* TOE */ -static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, +static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, size_t pktlen, wl_event_msg_t *event_ptr, void **data_ptr); #if defined(CONFIG_PM_SLEEP) @@ -4487,6 +4487,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) #else skb->mac.raw, #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ + len - 2, &event, &data); @@ -10279,16 +10280,16 @@ dhd_get_wireless_stats(struct net_device *dev) #endif /* defined(WL_WIRELESS_EXT) */ static int -dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, +dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, size_t pktlen, wl_event_msg_t *event, void **data) { int bcmerror = 0; ASSERT(dhd != NULL); #ifdef SHOW_LOGTRACE - bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, &dhd->event_data); + bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, &dhd->event_data); #else - bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, NULL); + bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, NULL); #endif /* SHOW_LOGTRACE */ if (bcmerror != BCME_OK) |