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

iwn_rx_compressed_ba: unbounded firmware-supplied qid indexes sc->txq[] and sc->qid2tap[] (OOB array access / NULL deref)

Summary

iwn_rx_compressed_ba at if_iwn.c:3266-3270: qid=le16toh(ba->qid) correctly byte-swapped at :3266 but lines 3267-3268 use RAW ba->qid (uint16) as array index into sc->txq[IWN5000_NTXQUEUES=20] and sc->qid2tap[20] with NO bounds check. tap=sc->qid2tap[ba->qid] dereferenced at :3269 without NULL check. Any firmware compressed_ba with qid>=20 OOB-reads both arrays; any compressed_ba for TID whose aggregation was torn down (qid2tap[qid]=NULL via iwn_ampdu_tx_stop :7532) causes NULL deref panic in interrupt thread. Reachable: associated AP/attacker sends DELBA then Compressed BlockAck for same TID. Remote DoS minimum, OOB memory corruption if OOB qid slot contains non-NULL value. Fix: bounds-check qid<sc->ntxqs and NULL-check tap before deref.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1122 Β· 7 files
FileTypeDescriptionSize
fix.diff suggested-fix bounds-check qid<sc->ntxqs, use swapped qid consistently, NULL-check tap before deref 1.3 KB view raw
iwn_fix_build.log build-log if_iwn.ko rebuilt from patched source (with DF-1123) under -Werror, rc=0 21.4 KB view raw
VERDICT.md verdict full line-by-line trace + fix rationale 3.0 KB ↓ raw
README.md readme why there is no .c trigger 1.4 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-1122 β€” iwn_rx_compressed_ba: unbounded firmware qid (OOB array read / NULL deref)

This finding has no userspace trigger: the bug is in the firmware-notification handler iwn_rx_compressed_ba (sys/dev/netif/iwn/if_iwn.c:3250-3270), invoked from the RX interrupt path when the Intel WiFi firmware posts a Compressed BlockAck notification. The qid field comes from firmware/DMA, not from any syscall. The realistic trigger is:

  • a hostile/buggy associated access point sending DELBA followed by a Compressed BlockAck for the same TID (so sc->qid2tap[qid] was NULLed by iwn_ampdu_tx_stop at if_iwn.c:7532), causing the NULL-deref panic at :3269 (tid = tap->txa_tid); or
  • a firmware/PHY notification with ba->qid >= IWN5000_NTXQUEUES (20), causing an out-of-bounds read of sc->txq[] (:3267) and sc->qid2tap[] (:3268).

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 hostile radio/firmware event, which cannot be synthesized without the NIC.

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

DF-1122 β€” VERDICT

Verdict

SOURCE-CONFIRMED (real bug), NOT REPRODUCED AT RUNTIME on this guest. The unbounded firmware qid index and the unchecked tap dereference are 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_compressed_ba (sys/dev/netif/iwn/if_iwn.c:3250-3270) handles a firmware Compressed BlockAck notification (RX interrupt path; ba is DMA'd from firmware): - :3266 qid = le16toh(ba->qid); β€” byte-swapped into the local qid. - :3267 txq = &sc->txq[ba->qid]; β€” indexes sc->txq[] (sized IWN5000_NTXQUEUES = 20, if_iwnvar.h:299) with the raw ba->qid (uint16_t, 0..65535) β€” no bounds check. - :3268 tap = sc->qid2tap[ba->qid]; β€” same raw index into sc->qid2tap[] (sized IWN5000_NTXQUEUES = 20, if_iwnvar.h:393) β€” no bounds check. - :3269 tid = tap->txa_tid; β€” dereferences tap without a NULL check.

Two consequences: 1. OOB array read β€” any notification with ba->qid >= 20 reads past both arrays. (On x86 le16toh is identity, so qid == ba->qid; the raw-vs-swapped mismatch is moot, but the missing bounds check is the bug regardless.) 2. NULL-deref panic β€” sc->qid2tap[qid] is set to NULL when aggregation is torn down: iwn_ampdu_tx_stop (if_iwn.c:7532) and :3303/:3874. A notification for a TID whose aggregation was torn down (hostile AP sends DELBA then a Compressed BlockAck for the same TID) makes tap == NULL β†’ panic in the interrupt thread. Remote DoS minimum; OOB memory corruption if the OOB qid2tap slot happens to hold a non-NULL value.

There is no userspace syscall trigger β€” the qid comes from firmware/DMA, not from any ioctl. The realistic trigger is a hostile/buggy associated AP or firmware.

Why not reproduced here

No Intel Wireless (iwn) hardware in the QEMU guest; if_iwn.ko is not loaded (kldstat shows only kernel/ehci/xhci) and never attaches, so the RX path is dead. The trigger cannot be synthesized without the NIC.

Fix

fix.diff bounds-checks qid >= sc->ntxqs (sc->ntxqs is the per-device queue count, 16 or 20, used consistently as the bound elsewhere β€” e.g. iwn_addba_request:7425), uses the byte-swapped qid consistently for both array indexes, and NULL-checks tap before dereferencing β€” returning early (with a debug print) in either case. Matches the finding's proposal.

Fix validation (compile)

Applies (git apply --check clean) and compiles: if_iwn.ko rebuilt from patched source (with DF-1123'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 remote DoS (NULL deref) / OOB read 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_compressed_ba raw ba->qid indexes txq[20]/qid2tap[20] unbounded + NULL tap deref. No WiFi HW.