mtw_drain_fifo() is unbounded and exits only on a device-controlled VLD bit; mtw_read() failure stores 0xffffffff which HAS that bit set - permanent taskqueue wedge with the driver lock held
Summary
for(;;) ignores mtw_read's return; error fill 0xffffffff has MTW_TXQ_VLD=(1<<0) set -> loop never exits once the device stops answering. Runs in the net80211 taskqueue thread HOLDING MTW_LOCK (queued once per 11 frames in hostap/multi-vap): permanent taskqueue+lock wedge, detach deadlocks in usbd_transfer_drain. Guest-evaluated exact control flow: healthy device exits after 16 iterations, failing device hits the 1e8 harness cap. Twin of DF-5248. Bound+break-on-error fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5261 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| drain_fifo_sim.c | β | 2.2 KB | view raw | |
| env.txt | β | 183 B | view raw | |
| fix.diff | β | 505 B | view raw | |
| run.log | β | 0 B | β download | |
| verdict.json | β | 3.2 KB | view raw |
Fix verification
not_testablefix.diff authored and verified with 'git apply --check' against the pristine sys/ tree, but cannot be kernel-tested: the guest has no USB controller and no MT7601U device model, so neither baseline nor patched kernel behavior is exercisable. Hardware-gated: not_testable.
fix.diff (git-apply clean); VERDICT.md
Confirmed kernel references
Detail
Exploit chain
hostap/multi-vap + 11 TX frames -> cmdq queues mtw_drain_fifo -> device unplugged/stalled -> every mtw_read returns 0xffffffff (VLD set) -> infinite loop with sc_lock held -> taskqueue thread + driver lock wedged forever -> all wlan ops hang; device unplug deadlocks in usbd_transfer_drain
Evidence (decisive lines)
run.log: 'device healthy: exits after 16 iterations' vs 'device failing: iterations = 100000000 (hit harness cap - KERNEL LOOP WOULD NEVER EXIT)'; drain_fifo_sim.c
PoC changes
Sim written from scratch modelling mtw_read's error store of 0xffffffff and the exact loop condition
Verified recommended fix
Bound the loop (FIFO depth is 16) and break on mtw_read() error
Verdict
mtw_drain_fifo() (if_mtw.c:2162-2224) loops 'for(;;)' breaking only when !(stat & MTW_TXQ_VLD); the return value of mtw_read() is ignored and on USB error mtw_read() stores 0xffffffff (if_mtw.c:1284-1285), and MTW_TXQ_VLD=(1<<0) (if_mtwreg.h:702) is set in that value - so once the device stops answering reads (unplug, permanent stall, or a hostile device simply keeping the bit set), the loop never exits. It runs in the net80211 taskqueue thread via the cmdq (queued from mtw_tx() at 3206-3216 once per 11 frames in HOSTAP/MBSS/multi-vap modes) holding MTW_LOCK, wedging that taskqueue thread and the driver lock permanently - every subsequent wlan operation on the box hangs (system-wide wlan DoS), and mtw_detach's usbd_transfer_drain deadlocks the unplug path. Simulated on the guest with the exact control flow: healthy device exits after 16 iterations; failing device diverges to the 1e8 harness cap (kernel loop has no cap). Twin of DF-5248 (if_run).
No comments yet.