DivestOS/Patches/Linux_CVEs/CVE-2017-0740/ANY/0.patch
2017-10-29 22:14:37 -04:00

111 lines
4.0 KiB
Diff

From e7fdc1ca00f1e589df8542af7e7acaaa87370625 Mon Sep 17 00:00:00 2001
From: Insun Song <insun.song@broadcom.com>
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 <insun.song@broadcom.com>
---
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