wpi_notif_intr RX index mask 0xfff wider than WPI_RX_RING_COUNT=64 can cause infinite softirq loop
Summary
wpi_notif_intr at if_wpi.c:2208-2212: hw=le32toh(shared->next)&0xfff (0..4095) but WPI_RX_RING_COUNT=64. If firmware writes value>63: while(rxq.cur!=hw) never terminates because rxq.cur cycles mod 64. Network stack hang. Fix: mask with (WPI_RX_RING_COUNT-1) instead of 0xfff.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1158 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | Replace & 0xfff with & (WPI_RX_RING_COUNT - 1) so firmware-supplied index cannot outrange the 64-entry ring | 431 B | view raw |
| VERDICT.md | verdict | full mechanism trace + reachability note | 3.3 KB | β raw |
| README.md | readme | summary + reproduce steps | 1.1 KB | β raw |
| build.sh | build-script | apply fix + build if_wpi.ko | 504 B | view raw |
| run.sh | run-script | placeholder runtime trigger (needs HW) | 1.0 KB | view raw |
| build.log | build-log | full successful build of patched if_wpi.ko | 1.1 KB | view raw |
| env.txt | environment | uname, cc, hw.model | 497 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 |
DF-1158 PoC verification β source-level trace of wpi_notif_intr index mask bug.
The driver is compiled into the X86_64_GENERIC kernel
(sys/config/X86_64_GENERIC:272) but no Intel 3945ABG WiFi HW is present in
the QEMU guest, so the vulnerable code path is not runtime-reachable here.
Verification is by source-level trace + build-validation of the fix.
Bug location
sys/dev/netif/wpi/if_wpi.c:2208βhw = le32toh(sc->shared->next) & 0xfff;WPI_RX_RING_COUNT = 64(sys/dev/netif/wpi/if_wpireg.h:25-30)sc->shared->nextis firmware-DMA-written (if_wpi.c:5347-5348,if_wpireg.h:233-237)
Mechanism
The kernel trusts 12 bits of a firmware-DMA word but iterates rxq.cur modulo
64, so any firmware value > 63 in the low 12 bits makes the while-loop at
if_wpi.c:2211 non-terminating. Kernel interrupt handler hangs β DoS.
Reproduce
- Apply
fix.diffto /usr/src. cd /usr/src/sys/dev/netif/wpi && make KMOD=if_wpiβ if_wpi.ko builds clean.- Runtime test requires Intel 3945ABG HW (not present on this guest).
See VERDICT.md for the full analysis.
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:
/* 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_LOGis6in non-DIAGNOSTICbuilds (sys/dev/netif/wpi/if_wpireg.h:27), soWPI_RX_RING_COUNT = 1<<6 = 64(if_wpireg.h:30).sc->shared->nextis auint32_twritten by the WiFi firmware over DMA (sys/dev/netif/wpi/if_wpireg.h:235, registered atif_wpi.c:5347-5348).- The kernel masks the firmware-supplied value with
0xfff(12 bits β 0..4095) but then iteratesrxq.curmoduloWPI_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 -lvshows 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_intris 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.
Fix verification
not_testablecompile validated
module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source+harness. wpi_notif_intr RX index mask 0xfff vs WPI_RX_RING_COUNT=64 -> infinite loop. wpi in GENERIC, no WiFi HW.
No comments yet.