DragonFlyBSD Kernel Audit
DF-1240 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/netif/iwi/if_iwi.c b/sys/dev/netif/iwi/if_iwi.c
index 0f1606cc..6422c71f 100644
--- a/sys/dev/netif/iwi/if_iwi.c
+++ b/sys/dev/netif/iwi/if_iwi.c
@@ -1551,9 +1551,35 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
 			DPRINTFN(2, ("Association succeeded\n"));
 			sc->flags |= IWI_FLAG_ASSOCIATED;
 			IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
-			iwi_checkforqos(vap,
-			    (const struct ieee80211_frame *)(assoc+1),
-			    le16toh(notif->len) - sizeof(*assoc) - 1);
+			{
+				int nl = le16toh(notif->len);
+				int qlen;
+				/*
+				 * notif->len is a firmware-supplied u16.
+				 * Guard the subtraction against underflow and
+				 * clamp the result to the space actually
+				 * present in the MCLBYTES rx cluster after the
+				 * iwi_hdr + iwi_notif + assoc prefix (offset
+				 * 28).  Without this, a malicious AP/firmware
+				 * can drive efrm well past the cluster in
+				 * iwi_checkforqos()'s IE walk (up to ~292B).
+				 */
+				if (nl >= (int)(sizeof(*assoc) + 1))
+					qlen = nl - sizeof(*assoc) - 1;
+				else
+					qlen = 0;
+				if (qlen > (int)(MCLBYTES -
+				    sizeof(struct iwi_hdr) -
+				    sizeof(struct iwi_notif) -
+				    sizeof(*assoc)))
+					qlen = MCLBYTES -
+					    sizeof(struct iwi_hdr) -
+					    sizeof(struct iwi_notif) -
+					    sizeof(*assoc);
+				iwi_checkforqos(vap,
+				    (const struct ieee80211_frame *)(assoc+1),
+				    qlen);
+			}
 			ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
 			break;
 		case IWI_ASSOC_INIT: