β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1123

iwn_rx_done: missing upper bound on firmware-reported frame length allows OOB read of RX mbuf / kernel heap

Summary

iwn_rx_done at if_iwn.c:3078/3081: len=le16toh(mpdu->len) or le16toh(stat->len) with only LOWER bound check (len>=sizeof(ieee80211_frame_ack)=10) at :3098. NO upper bound check against IWN_RBUF_SIZE=4096. Line 3084: flags=le32toh(*(uint32_t*)(head+len)) reads up to ~60KB past 4KB RX cluster for len up to 65535. Lines 3156-3157: m_data=head, m_pkthdr.len=m_len=len, fabricates mbuf spanning ~60KB but physically in 4KB cluster. ieee80211_input at :3231 walks len bytes of attacker-influenced-size -> kernel heap info leak or panic. Triggered by firmware bug misreporting len or DMA-injection. Fix: check head+len+4 <= IWN_RBUF_SIZE before FCS read.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1123 Β· 7 files
FileTypeDescriptionSize
fix.diff suggested-fix upper-bound len against IWN_RBUF_SIZE before the FCS read; bump ic_ierrors and return 1.0 KB view raw
iwn_fix_build.log build-log if_iwn.ko rebuilt from patched source (with DF-1122) under -Werror, rc=0 21.4 KB view raw
VERDICT.md verdict full line-by-line trace + fix rationale 2.5 KB ↓ raw
README.md readme why there is no .c trigger 1.5 KB ↓ raw
env.txt environment uname, cc version, kldstat 383 B 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
README.md readme why there is no .c trigger
↓ download raw

DF-1123 β€” iwn_rx_done: missing upper bound on firmware-reported frame length (OOB read / heap overflow)

This finding has no userspace trigger: the bug is in iwn_rx_done (sys/dev/netif/iwn/if_iwn.c:3078-3157), the RX-done notification handler run from the iwn interrupt thread. The frame length len is taken from firmware (le16toh(mpdu->len) / le16toh(stat->len)) and only lower-bounded (len >= sizeof(ieee80211_frame_ack), :3098). There is no upper bound against the 4 KB RX cluster (IWN_RBUF_SIZE = 4096), so a buggy or hostile firmware/PHY reporting len up to 65535 causes:

  • :3084 flags = le32toh(*(uint32_t *)(head + len)) β€” reads up to ~60 KB past the 4 KB DMA cluster (heap OOB read); and
  • :3156-3157 m->m_data = head; m->m_pkthdr.len = m->m_len = len β€” fabricates an mbuf claiming a ~60 KB body inside a 4 KB cluster, so ieee80211_input (:3231) walks attacker-influenced-size bytes => heap info leak or panic.

Preconditions on this guest: if_iwn.ko ships in /boot/kernel but is NOT loaded and there is no Intel Wireless (iwn) hardware in the QEMU guest, so the driver never attaches and the RX path is dead. The bug is therefore source-confirmed latent β€” real in compiled module code, unreachable at runtime here. See VERDICT.md for the line-by-line trace.

There is no .c trigger file because no syscall drives the path; the trigger is a firmware/PHY event (a misreported RX length), which cannot be synthesized without the NIC.

VERDICT.md verdict full line-by-line trace + fix rationale
↓ download raw

DF-1123 β€” VERDICT

Verdict

SOURCE-CONFIRMED (real bug), NOT REPRODUCED AT RUNTIME on this guest. The missing upper bound on the firmware-reported frame length is traced line-by-line in compiled module source. It does not fire here because the iwn driver never attaches (no Intel WiFi HW). Dormant code path, not a false positive (if_iwn.ko ships in /boot/kernel).

Mechanism (source trace)

iwn_rx_done (sys/dev/netif/iwn/if_iwn.c:3036-3157) processes an RX_DONE / MPDU_RX_DONE firmware notification (RX interrupt path): - :3080 len = le16toh(mpdu->len); or :3081 len = le16toh(stat->len); β€” firmware-reported 16-bit frame length. - :3084 flags = le32toh(*(uint32_t *)(head + len)); β€” reads 4 bytes at head + len. head sits inside data->m's IWN_RBUF_SIZE (4096, if_iwnreg.h:54) DMA cluster. There is no upper bound on len, so a buggy/hostile firmware reporting len up to 65535 reads up to ~60 KB past the 4 KB cluster (heap OOB read). - :3098 the only length check is a lower bound: len < sizeof(struct ieee80211_frame_ack) (10 bytes) β€” discards too-short frames but never too-long. - :3156-3157 m->m_data = head; m->m_pkthdr.len = m->m_len = len; fabricates an mbuf claiming a ~60 KB body inside a 4 KB cluster, so ieee80211_input (:3231) walks attacker-influenced-size bytes β†’ heap info leak or panic.

Trigger: a firmware/PHY event misreporting the RX length (firmware bug or DMA injection by a hostile radio). There is no userspace syscall trigger.

Why not reproduced here

No Intel Wireless (iwn) hardware; if_iwn.ko not loaded and never attaches; the RX path is dead. Cannot be synthesized without the NIC.

Fix

fix.diff adds an explicit upper bound before the FCS read: reject if len > IWN_RBUF_SIZE or head + len + sizeof(uint32_t) would exceed mtod(data->m) + IWN_RBUF_SIZE (the cluster end), bumping ic_ierrors and returning. Matches the finding's proposal (check head+len+4 against the RX buffer size).

Fix validation (compile)

Applies (git apply --check clean) and compiles: if_iwn.ko rebuilt from patched source (with DF-1122's fix also applied) under -Werror, if_iwn.c compiled clean, rc=0. Runtime before/after is not_testable (no iwn HW; the trigger is a firmware/radio event that cannot be synthesized here).

Exploit chain

None β€” the primitive is firmware/radio-triggered and unreachable at runtime on this guest; impact ceiling is OOB heap read / fabricated-mbuf info leak or panic on a HW-equipped host.

Fix verification

not_testable

compile validated -Werror

module rebuild rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. iwn_rx_done len no upper bound vs IWN_RBUF_SIZE -> OOB FCS read + fabricated mbuf. No WiFi HW.