From e7fdc1ca00f1e589df8542af7e7acaaa87370625 Mon Sep 17 00:00:00 2001 From: Insun Song Date: Fri, 7 Apr 2017 16:27:49 -0700 Subject: [PATCH] net: wireless: bcmdhd: additional length check for BRCM EVENT frame. This is just for exceptional case where user has updated kernel to the latest, but still used non-patched firmware. The non-patched firmware could deliver ETHER_TYPE_BRCM packet to host. If attacker inject packet with its header length forged, it could bypass current host driver's length check routine and cause memory corruption. Proposed fix is enhancing length check to validate its header length. Change-Id: I90fc5101bddfd1d427e0a52758ddf8bc16577555 Bug: 37168488 Signed-off-by: Insun Song --- drivers/net/wireless/bcmdhd/bcmevent.c | 27 ++++++++++++++-------- drivers/net/wireless/bcmdhd/include/proto/bcmeth.h | 1 + 2 files changed, 18 insertions(+), 10 deletions(-) mode change 100755 => 100644 drivers/net/wireless/bcmdhd/include/proto/bcmeth.h diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index b85f111bce180..7ed9739c0eddf 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -209,12 +209,14 @@ int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, bcm_event_msg_u_t *out_event) { - uint16 len; + uint16 evlen; uint16 subtype; uint16 usr_subtype; bcm_event_t *bcm_event; uint8 *pktend; + uint8 *evend; int err = BCME_OK; + uint32 data_len; pktend = (uint8 *)pktdata + pktlen; bcm_event = (bcm_event_t *)pktdata; @@ -235,8 +237,9 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, } /* check length in bcmeth_hdr */ - len = ntoh16_ua((void *)&bcm_event->bcm_hdr.length); - if (((uint8 *)&bcm_event->bcm_hdr.version + len) > pktend) { + evlen = ntoh16_ua((void *)&bcm_event->bcm_hdr.length); + evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; + if (evend != pktend) { err = BCME_BADLEN; goto done; } @@ -257,13 +260,15 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); switch (usr_subtype) { case BCMILCP_BCM_SUBTYPE_EVENT: - if (pktlen < sizeof(bcm_event_t)) { + if ((pktlen < sizeof(bcm_event_t)) || + (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { err = BCME_BADLEN; goto done; } - len = sizeof(bcm_event_t) + ntoh32_ua((void *)&bcm_event->event.datalen); - if ((uint8 *)pktdata + len > pktend) { + data_len = ntoh32_ua((void *)&bcm_event->event.datalen); + if ((sizeof(bcm_event_t) + data_len + + BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) { err = BCME_BADLEN; goto done; } @@ -280,14 +285,16 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, break; case BCMILCP_BCM_SUBTYPE_DNGLEVENT: - if (pktlen < sizeof(bcm_dngl_event_t)) { + if (pktlen < sizeof(bcm_dngl_event_t) || + (evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) { err = BCME_BADLEN; goto done; } - len = sizeof(bcm_dngl_event_t) + - ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen); - if ((uint8 *)pktdata + len > pktend) { + data_len = ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata) + ->dngl_event.datalen); + if ((sizeof(bcm_dngl_event_t) + data_len + + BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) { err = BCME_BADLEN; goto done; } diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h old mode 100755 new mode 100644 index 41c1b57443c77..756f594bc61db --- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h @@ -93,6 +93,7 @@ #define BCMILCP_BCM_SUBTYPE_DNGLEVENT 5 #define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 #define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 +#define BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD 2 /* These fields are stored in network order */ typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr