# DF-1158 — wpi_notif_intr RX index mask wider than ring (source-only verification)

## Verdict: REPRODUCED at source level (latent in compiled-in code; not triggerable without Intel 3945ABG WiFi HW)

## Mechanism

`wpi(4)` is a statically-compiled-in driver in `X86_64_GENERIC`
(`sys/config/X86_64_GENERIC:272`). The RX completion handler reads the
firmware-owned index from shared DMA memory:

```c
/* sys/dev/netif/wpi/if_wpi.c:2208 */
hw = le32toh(sc->shared->next) & 0xfff;          /* mask allows 0..4095 */
hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; /* WPI_RX_RING_COUNT = 64 */

while (sc->rxq.cur != hw) {                       /* unreachable exit */
    sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;   /* stays in 0..63 */
    ...
}
```

- `WPI_RX_RING_COUNT_LOG` is `6` in non-`DIAGNOSTIC` builds
  (`sys/dev/netif/wpi/if_wpireg.h:27`), so `WPI_RX_RING_COUNT = 1<<6 = 64`
  (`if_wpireg.h:30`).
- `sc->shared->next` is a `uint32_t` written by the WiFi firmware over DMA
  (`sys/dev/netif/wpi/if_wpireg.h:235`, registered at `if_wpi.c:5347-5348`).
- The kernel masks the firmware-supplied value with `0xfff` (12 bits → 0..4095)
  but then iterates `rxq.cur` modulo `WPI_RX_RING_COUNT` (0..63).

**Effect:** If the firmware (buggy, malicious, or wrong chip variant) ever
writes a value whose low 12 bits exceed 63, the while-loop's exit condition
`rxq.cur == hw` becomes unreachable: `rxq.cur` cycles 0..63 forever, while
`hw` is stuck at some value ≥ 64. The interrupt handler never returns → kernel
hang (DoS). The ring-config register tells the firmware `WPI_RX_RING_COUNT_LOG`
(`if_wpi.c:5356`) but the kernel nonetheless trusts up to 12 bits of an
attacker-influenced DMA word.

## Trigger reachability on this guest

- No Intel PRO/Wireless 3945ABG (wpi) device is present in the QEMU guest.
  `pciconf -lv` shows no such NIC; the driver attaches to no device.
- The vulnerable code is present in the running kernel (compiled-in), but the
  RX-completion interrupt `wpi_notif_intr` is only entered from the device's
  interrupt handler, which never fires without the HW.
- Therefore the bug is **not runtime-triggerable on this guest** — it is a
  defensive / latent hardening defect that requires real (or emulated) wpi HW.

## Fix

`fix.diff` replaces `& 0xfff` with `& (WPI_RX_RING_COUNT - 1)` (=`& 0x3f`) so
that no firmware-supplied value can outrange the actual ring. The next two
lines (`(hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1`) and the loop predicate
then become provably terminating. This matches the analogous masking done by
`iwm(4)` / `iwn(4)` in their RX completion handlers.

## Build verification of the fix

`if_wpi.ko` built successfully from the patched source on the guest
(`cc 8.3 [DragonFly]`):
```
--- if_wpi.ko ---
cc -Wl,--build-id=sha1 -nostdlib -Wl,--hash-style=sysv   -r -Wl,-d -o if_wpi.ko if_wpi.o
BUILD_EXIT=0
```
Full output: `build.log`. The fix is build-clean (no warnings/errors).

## Fix-validation status

`not_testable` — the bug requires Intel 3945ABG WiFi HW (or a faithful emulator
that drives the firmware DMA descriptor) to runtime-trigger. The guest has
neither. We confirmed the fix **applies cleanly** and the patched module
**compiles** with `cc 8.3` against the audit source tree; the change is a
one-character mask correction with no behavioral side-effect on the
well-behaved-firmware path.
