net: wireless: bcmdhd: additional length check for BRCM EVENT frame.

(cherry picked from commit 72c9463eaab0fa19a461ac8de7d0abbf825a44bd)

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.

Signed-off-by: Insun Song <insun.song@broadcom.com>
Bug: 37168488
Change-Id: I90fc5101bddfd1d427e0a52758ddf8bc16577555
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index b85f111..7ed9739 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -209,12 +209,14 @@
 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 @@
 	}
 
 	/* 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 @@
 	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 @@
 
 		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 41c1b57..756f594
--- 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