# DF-4142 VERDICT — wi_rx_intr: ignored wi_read_bap() return → uninitialized heap in delivered frames

**Status: inconclusive (hardware-gated; no wi(4) NIC on the guest). Defect
existence certain at source level; no kernel-write primitive; ceiling is a
device-triggered kernel-heap info disclosure into received frames.**

## Trace

- `wi_intr()` (if_wi.c:594) takes WI_LOCK and dispatches RX events to
  `wi_rx_intr()` (:614).
- `wi_rx_intr()` reads the 60-byte `struct wi_frame` header from the NIC
  FID with a **checked** read (:1293-1302 — error → ACK, count, return).
- `len = le16toh(frmhdr.wi_dat_len)` (:1319) — firmware-fed u16;
  correctly bounded against MCLBYTES/MHLEN (:1326-1343); monitor-mode
  oversized frames are truncated to len=0 (:1337). No length bug.
- mbuf is allocated (`m_getcl`/`m_gethdr`, :1340-1343), the 24-byte 802.11
  header is memcpy'd from the (already-verified) `frmhdr.wi_whdr`
  (:1354-1355), then the body copy at **:1356 ignores the
  `wi_read_bap()` return value**.
- `wi_read_bap()` (if_wi.c:1901-1916) fails on BAP seek timeout / OFF_ERR
  (`wi_seek_bap` :1868-1899 sets `sc->sc_bap_off = WI_OFF_ERR` and returns
  ETIMEDOUT/EIO), after which `wi_rx_intr` continues with an mbuf whose
  `m_pkthdr.len` claims `24 + len` bytes (:1358) while the tail was never
  (or only partially) transferred.
- The mbuf is then delivered to `ieee80211_input()` (:1390-1395); BPF taps
  see it through the normal 802.11 receive path; monitor-mode vaps pass the
  raw frame up unchanged.

Uninitialized bytes come from freshly allocated (unzeroed) mbuf clusters or
mbuf clusters recycled from prior traffic — the classic stale-kernel-heap
disclosure shape.

## Why inconclusive, not not_reproduced

The defect cannot be triggered on this guest: no Prism/Hermes hardware is
present (`pciconf -l | grep -ci 'atheros|prism|…'` = 0; no wi interface),
and triggering requires a device that faults a BAP transfer mid-frame.
There is nothing to "fail to reproduce" — the code path is unconditional
whenever the device misbehaves; the C-level defect (ignored return) is
directly visible at :1356 with every adjacent error path (:1293, :1344)
doing the check properly.

## Pass-2 areas hunted in if_wi.c — results (negative result weight)

Prompt-directed areas, with dispositions:

- (a) wi_read_record/wi_write_record RID walks: **do not exist** in
  DragonFly's wi driver — the legacy wi_ioctl/SIOC[SG]PRISMSTATS record
  machinery was removed in the net80211 conversion (rg over
  sys/dev/netif/wi/: zero matches for wi_read_record|wi_write_record|
  wi_ioctl|wi_getdbg). Dead surface.
- (b) wi_in_scan Prism2 scan-RID walks: **do not exist** (same removal).
- (c) 802.11 compat ioctl conversions: driver installs **no if_ioctl
  handler**; SIOCS80211 is handled by net80211. MTU clamped to
  IEEE80211_MTU_MAX=2290 (netproto/802_11/wlan/ieee80211_ioctl.c:3481-3487)
  and SIOCSIFMTU requires SYSCAP_RESTRICTEDROOT (sys/net/if.c:2261).
- (d) join/assoc result handling: `wi_newstate_sta` JOIN_REQ writes a
  fixed-size `wi_joinreq` (:844-850); `wi_info_intr` LINK_STAT checks
  `vap == NULL` (:1500) before deref; COUNTERS loop is bounded by
  `sizeof(sc->sc_stats)/4` (:1538) with `min()` — though `ltbuf`/`stat`
  are uninit-read candidates if the device returns garbage (device-fed,
  control-flow only, no memory unsafety — noted, not filed).
- (e) rx frame header parse: bounded (see above); the ignored BAP return is
  this finding. `wi_tx_ex_intr` checks its read (:1408).
- (f) tx fid list: `wi_tx_intr` validates the alloc FID against
  `sc_txd[cur].d_fid` (:1463); partial `wi_alloc_fid` failure in
  `wi_setup_locked` (:664-674) aborts init before RUNNING is set, and
  `wi_reset` reinitializes the NIC — no kernel memory issue.
- (g) monitor header prepend paths: DragonFly's copy has no prism2 monitor
  header prepend (radiotap fields filled from frmhdr only, :1364-1380).

Additional candidates killed:

- `wi_write_txrate` `rates[tp->ucastrate / 2]` OOB (:1740-1742): ucastrate
  is validated by `checkrate()` against the 11b rateset with 0x7f mask
  (ieee80211_ioctl.c:2180-2190, :2231-2235) → index ≤ 11 of 12. Killed.
- `wi_mwrite_bap` → `m_copydata(m, 0, totlen, sc->sc_txbuf[2304])`
  (:1950): MTU ≤ 2290 + LLC 8 + WEP 8 − stripped 24-byte header = 2282 ≤
  2304 (driver is WEP-only: ic_cryptocaps=WEP, if_wi.c:431). Killed.
- `wi_attach` ratebuf/`val` uninit reads when RID len < 2 (:357, :436):
  device-fed, nrates capped (:438-439), no OOB; not filed.
- `wi_write_appie` 40-byte cap checked (:2051). OK.
- `wi_read_nicid` bounded reads (memset + fixed 8/12-byte buffers). OK.
- DF-1400 (wi_write_wep LUCENT key overflow, :1751-1769) — known, excluded.

## Recommended fix

fix.diff (in this pack): check the `wi_read_bap()` return at :1356; on
failure free the mbuf, ACK WI_EV_RX, bump ic_ierrors, and return — exactly
the pattern of the two adjacent error paths.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
