DF-5292 / verdict.json
{ "finding_id": "DF-5292", "status": "inconclusive", "reproduced": false, "impact": "none", "confidence": "likely", "verdict": "Beacon-mbuf write-after-free, rums instance of the run/urtwn/mtw twin family (DF-5246/DF-5254/DF-5259). rum_update_beacon() (if_rum.c:2792-2831) drops RUM_LOCK at :2825 and ieee80211_beacon_update() at :2828 writes seq/capinfo/TIM/ERP data into rvp->bcn_mbufs 2KB cluster under the net80211 ic lock only, while rum_newstate() (:932-933 drops the ic lock, takes RUM_LOCK; S_RUN -> rum_alloc_beacon :977 -> m_freem at :2775-2776) and rum_vap_delete() (m_freem at :715 with NO lock) free the same cluster in disjoint lock domains. IEEE80211_LOCK is a per-ic lockmgr mutex (ieee80211_dragonfly.h:598), not a global serializer, so the domains really are disjoint. In-kernel reproduction is hardware-gated (no RT2573 device can attach to the QEMU guest; audited source is md5-identical to the guest tree and if_rum.ko loads). Simulated on the guest with a line-faithful 3-thread lock-domain model: freed-in-window UAF writes 1/9/3 (base) and 5/2/13 (with preemption yield) per 3x10s runs - reachable in 6/6 runs; the userspace write burst is the optimistic floor, the in-kernel TIM/element recompute window is microseconds and unbounded under preemption.", "exploit_chain": "hostap/ibss vap + power-save client TIM churn / ERP/CSA beacon updates (remote-peer assistable) racing ifconfig down/destroy or an S_RUN re-entry -> ieee80211_beacon_update writes seqno/capinfo/TIM bitmap into a freed 2KB mbuf cluster -> heap corruption -> panic; with post-free reallocation control of the 2KB zone -> controlled overwrite -> privesc potential", "evidence": "run.log: freed-in-window UAF WRITES=1/9/3 then 5/2/13 across 3+3 runs (nonzero every run); rum_beacon_race.c models :2800/:2803-2825/:2828 vs :932-933/:2775-2776 vs :715 with two mutexes and a lock-free deleter; VERDICT.md lock-intersection table", "kernel_refs": [ "sys/bus/u4b/wlan/if_rum.c:2800", "sys/bus/u4b/wlan/if_rum.c:2825", "sys/bus/u4b/wlan/if_rum.c:2828", "sys/bus/u4b/wlan/if_rum.c:932", "sys/bus/u4b/wlan/if_rum.c:977", "sys/bus/u4b/wlan/if_rum.c:2775", "sys/bus/u4b/wlan/if_rum.c:715", "sys/netproto/802_11/wlan/ieee80211_output.c:3339", "sys/netproto/802_11/ieee80211_dragonfly.h:598" ], "poc_changes": "Harness written from scratch (no seed); pthread mutexes model IEEE80211_LOCK(ic) and RUM_LOCK(sc); the deleter thread is deliberately lock-free exactly like rum_vap_delete:715; an atomic poison flag counts would-be UAF writes without killing the run; a sched_yield variant models preemption", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 90, "guest_dirty": 0, "build_cmd": "cc -O2 -pthread -Wall -o rum_beacon_race rum_beacon_race.c", "run_cmd": "./rum_beacon_race 10 (3 runs; plus 3 preemption-mode runs - see run.log)", "code_hash": "9710848eccb256ab3dccb6f089f85de66966f987d9e7ef7e169d4ac2199dc9b7", "notes": "Hardware-gated like the whole wlan family this pass (methodology of DF-5246..DF-5267). kldload if_rum.ko confirmed the audited object is the running builds module (kldstat id 4); module was unloaded afterwards. The DF-5292 fix and the DF-5293 fix both touch rum_vap_delete and merge trivially.", "recommended_fix": "Hold RUM_LOCK across the beacon_update in-mbuf writes in rum_update_beacon() and around the m_freem in rum_vap_delete()", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored and verified with git apply --check against the pristine sys/ tree; kernel-testing is impossible on this guest (no USB passthrough / RT2573 device model), so neither baseline nor patched kernel behavior is exercisable. Hardware-gated: not_testable.", "fix_evidence": "fix.diff (git-apply clean); VERDICT.md lock-order note (ic->sc is the established direction; RUM_LOCK is LK_CANRECURSE)" } |