β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5260

Deferred mtw_cmdq entries hold raw vap/ni pointers; mtw_vap_delete frees the mtw_vap without draining sc->cmdq_task - mtw_update_beacon_cb/mtw_newassoc_cb/mtw_key_set_cb execute on freed objects

Summary

7 producers stash raw vap/ni pointers in the 16-slot lockless ring; vap_delete kfree's rvp with no draintask (only mtw_detach drains) - pending entries run callbacks on freed 80211_VAP memory (iv_bss read, beacon built from freed heap, ni_macaddr read). Guest sim: 898/898 hit rate when vap_delete does not drain. Twin of DF-5247. draintask-before-free fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5260 Β· 5 files
FileTypeDescriptionSize
cmdq_race.c β€” 7.2 KB view raw
env.txt β€” 183 B view raw
fix.diff β€” 442 B view raw
run.log β€” 0 B ↓ download
verdict.json β€” 3.3 KB view raw

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

fix.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
↓ fix.diffper-fix-DF-5260

Confirmed kernel references

Detail

Exploit chain

wpa/hostap activity queues cmdq entries -> ifconfig wlanX destroy immediately -> kfree(rvp) while cmdq_task pending -> mtw_update_beacon_cb reads vap->iv_bss, rvp->beacon_mbuf from freed 80211_VAP zone memory -> info leak into device writes (beacon content from freed heap) / crash; ni variant -> UAF read of node macaddr

Evidence (decisive lines)

run.log: 'mtw_update_beacon_cb on freed vap hits: 898' (898/898 hit rate); cmdq_race.c vap mode; VERDICT.md

PoC changes

Harness written from scratch; consumer mirrors mtw_cmdq_cb (if_mtw.c:920-947) under a modelled MTW_LOCK; poison-flag instead of free so hits are countable

Verified recommended fix

ieee80211_draintask(ic, &sc->cmdq_task) in mtw_vap_delete() before the vap is freed

Verdict

mtw_update_beacon() queues {func=mtw_update_beacon_cb, arg0=vap} (if_mtw.c:3864-3865), mtw_newassoc() queues arg1=ni (2382-2386), mtw_key_set() queues arg1=vap (1937-1940), and the tx-timeout path queues arg0=vap (2887-2892) - all raw pointers into a 16-slot lockless ring consumed later by the cmdq task. mtw_vap_delete() (876-910) does ieee80211_vap_detach(vap) and kfree(rvp) at 909 with NO drain of sc->cmdq_task (ieee80211_draintask is only called from mtw_detach, 750-751), so any entry still pending when the vap is destroyed executes its callback on freed memory: mtw_update_beacon_cb dereferences vap->iv_bss (3876) and rvp->beacon_mbuf (3893-3898); mtw_newassoc_cb dereferences ni->ni_vap and ni->ni_macaddr (2340-2347) and indexes sc->wcid_stats[wcid]. Simulated on the guest: with the driver's exact queue/execute ordering, 898/898 queued beacon callbacks executed on a freed vap (every queued entry hits when vap_delete does not drain - the kernel's taskqueue latency vs. destroy window). In-kernel reproduction hardware-gated.