DF-1240 / fix.diff
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: |