iwi_checkforqos unbounded notif->len allows up to 292-byte OOB read past RX mbuf on crafted ASSOC RESP
Summary
iwi_notification_intr at if_iwi.c:1554-1556: calls iwi_checkforqos with len=le16toh(notif->len)-sizeof(assoc)-1. Embedded ASSOC RESP frame at cluster offset 28 (iwi_hdr+notif+assoc). notif->len from firmware up to 65535, iwi_checkforqos guard at :1378 only enforces len<IEEE80211_MAX_LEN(2313). len=2312 -> efrm=cluster+28+2312=cluster+2340, 292B past 2048B cluster. IE walk at :1401-1410 derefs frm[0]/frm[1]/iswmeoui(frm)[4B] in OOB region. Rogue AP pads ASSOC RESP with vendor IEs to ~2312B. Fix: clamp len to MCLBYTES-28.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1240 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | guard underflow + clamp notif->len to cluster space before calling iwi_checkforqos | 1.5 KB | view raw |
| VERDICT.md | verdict | source-level trace of ~292B OOB read + dead-code analysis | 2.7 KB | β raw |
| build.sh | build-script | applies fix, builds if_iwi.ko module | 339 B | view raw |
| run.sh | run-script | explains no-trigger on this guest | 613 B | view raw |
| env.txt | environment | uname, cc version, PCI inventory | 553 B | view raw |
| build.log | build-log | kernel build log excerpt proving -Werror clean compile of patched source | 31.3 KB | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1240 β iwi_checkforqos unbounded notif->len (OOB read up to ~292B)
Verdict: NOT REPRODUCED (dead code at runtime β no hardware)
Mechanism (source-level, confirmed real)
iwi_notification_intr() at sys/dev/netif/iwi/if_iwi.c:1455 handles
firmware notifications. For the ASSOCIATION notification, it calls:
// line 1545-1556
assoc = (struct iwi_notif_association *)(notif + 1);
switch (assoc->state) {
case IWI_ASSOC_SUCCESS:
...
iwi_checkforqos(vap,
(const struct ieee80211_frame *)(assoc+1),
le16toh(notif->len) - sizeof(*assoc) - 1); // <-- len from firmware
notif->len is a firmware-supplied uint16_t (0β65535). The subtraction
le16toh(notif->len) - sizeof(*assoc) - 1 can also underflow to a huge
int value if notif->len < 13.
Inside iwi_checkforqos (line 1368), the guard at 1378 is too loose:
if (!(sizeof(*wh)+8 < len && len < IEEE80211_MAX_LEN) || ...) // IEEE80211_MAX_LEN=2313
return;
frm = (const uint8_t *)&wh[1];
efrm = ((const uint8_t *) wh) + len; // <-- can point past cluster
The frame wh = (assoc+1) sits at cluster offset 28 (iwi_hdr=4 +
iwi_notif=12 + assoc=12). The cluster is MCLBYTES (2048). So safe
len max = 2048 β 28 = 2020. But the guard allows up to 2312, which
is 292 bytes past the cluster. The IE walk at lines 1401β1410
dereferences frm[] and efrm which are now OOB in the mbuf cluster /
adjacent kernel heap.
Struct sizes confirmed: iwi_hdr=4B, iwi_notif=12B (reserved[2]=8
+ type=1 + flags=1 + len=2), iwi_notif_association=12B (state=1 +
pad[11]=11). Prefix before frame = 4+12+12 = 28B.
The bug is real in source. A malicious AP / compromised firmware can
drive efrm up to ~292 bytes past the DMA cluster, causing an OOB read
in iwi_checkforqos.
Why it cannot reproduce on this guest
Same as DF-1239: iwi (Intel PRO/Wireless 2200BG/2915ABG) is not in
GENERIC, not loaded, no WiFi hardware on the QEMU guest. The
notification interrupt path is unreachable.
Valid hard blocker: dead/unreachable at runtime. Threat model is a malicious WiFi AP or compromised firmware on a real system with the card.
Fix
fix.diff guards the subtraction against underflow and clamps the
result to the actual cluster space (MCLBYTES - sizeof(iwi_hdr) -
sizeof(iwi_notif) - sizeof(*assoc) = 2020). Compiled successfully as
if_iwi.ko.
Impact
- On this guest: none (dead code, no WiFi hardware).
- On a real system: OOB read of up to ~292 bytes of kernel heap per association-response notification, from a remote (radio-range) attacker via a malicious AP. Could leak kernel pointers (defeating KASLR on systems that have it) or adjacent slab data. Low real-world prevalence due to the old (2004-era) hardware.
Fix verification
not_testablecompile validated
module/kernel build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. iwi_checkforqos IEEE80211_MAX_LEN vs cluster-28 -> ~292B OOB read. iwi NOT in GENERIC, no WiFi HW.
No comments yet.