# 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.
