rum_tx_mgt() pops a tx_free slot before validating the frame; the ENOENT/ENOBUFS error paths orphan it permanently - seven privileged raw injections wedge the TX path until down/up
Summary
tx_mgt pops the shared slot BEFORE Protected/key validation whose error paths abandon it: 7 errors (LIST_COUNT=8, MINFREE=2) wedge TX until admin down/up. Sibling tx_data validates BEFORE its pop - ordering defect unique to tx_mgt. Guest state-machine model: wedged after exactly 7 injections, restored by down/up. Move-the-pop fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5295 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| rum_txslot_leak.c | β | 3.5 KB | view raw | |
| build.sh | β | 104 B | view raw | |
| run.sh | β | 98 B | view raw | |
| build.log | β | 16 B | view raw | |
| run.log | β | 258 B | view raw | |
| env.txt | β | 241 B | view raw | |
| VERDICT.md | β | 2.4 KB | β raw | |
| README.md | β | 2.3 KB | β raw | |
| fix.diff | β | 748 B | view raw | |
| verdict.json | β | 3.4 KB | view raw |
DF-5295 β rum_tx_mgt() permanently orphans a tx_data slot on its
early-error paths (TX path exhaustion)
What
sys/bus/u4b/wlan/if_rum.c:1478-1494
data = STAILQ_FIRST(&sc->tx_free);
STAILQ_REMOVE_HEAD(&sc->tx_free, next);
sc->tx_nfree--; <-- slot popped FIRST
wh = mtod(m0, struct ieee80211_frame *);
...
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
k = ieee80211_crypto_get_txkey(ni, m0);
if (k == NULL)
return (ENOENT); <-- slot orphaned forever
if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
!k->wk_cipher->ic_encap(k, m0))
return (ENOBUFS); <-- slot orphaned forever
The entry is off tx_free, never goes to tx_q, holds no mbuf; nothing
ever increments tx_nfree for it again. RUM_TX_LIST_COUNT is 8 and
RUM_TX_MINFREE is 2 (if_rumvar.h:29-30), so:
rum_start()(:1734) gates ontx_nfree >= RUM_TX_MINFREEβ after 7 orphaned slots the interface stops dequeuing frames entirely;rum_raw_xmit()(:3055) gates the raw path the same way;- only
rum_init()βrum_setup_tx_list()(:2577/:787-804) restores the list, i.e. recovery needsifconfig down/up.
Sibling comparison: rum_tx_data() performs the same key checks at
:1631-1645 BEFORE its pop (:1670) and m_freem()s on error β the
pop-before-validate ordering is unique to rum_tx_mgt.
Trigger: raw 802.11 management frame with the Protected flag set and no
matching key (or a failing SWCRYPT encap) through the legacy
rum_raw_xmit() path (params == NULL, :3060-3065) β i.e. bpf raw injection
on the wlan interface (privileged: /dev/bpf is root-only). The caller
(ieee80211_raw_output, ieee80211_output.c:631-639) frees the mbuf and the
node on error β only the slot leaks.
Hardware gating
Deterministic driver-logic bug; rum(4) needs absent RT2573 hardware.
rum_txslot_leak.c is an exact state-machine model of the pop/error/gate
logic. Guest output (run.log): wedge after exactly 7 injections; only
down/up resets.
Build / Run / Expected
cc -O2 -Wall -o rum_txslot_leak rum_txslot_leak.c && ./rum_txslot_leak
Expected: TX path wedged after 7 injections ...; after ifconfig down/up:
tx_nfree=8.
Fix
fix.diff β move the pop after the validation block (mirror of
rum_tx_data). git apply --check clean. Kernel fix validation
hardware-gated (fix_status: not_testable).
DF-5295 VERDICT β deterministic tx_free slot leak in rum_tx_mgt
Status: inconclusive (hardware-gated). Bug: real, deterministic.
Why the bug is certain from source alone
rum_tx_mgt pops the tx_free head and decrements tx_nfree
(if_rum.c:1478-1480) before validating the frame; the two error returns at
:1490 (ENOENT: Protected mgmt frame, ieee80211_crypto_get_txkey β NULL)
and :1494 (ENOBUFS: SWCRYPT ic_encap failure) abandon the popped entry
with no list insertion and no compensating tx_nfree++. With
RUM_TX_LIST_COUNT=8 / RUM_TX_MINFREE=2 (if_rumvar.h:29-30), seven such
errors wedge the TX path (rum_start:1734 gate) until
rum_initβrum_setup_tx_list (:2577) runs (down/up). The mbuf and node
are correctly freed by the caller (ieee80211_raw_output,
net80211/wlan/ieee80211_output.c:631-639) β the leak is the slot alone.
Reachability: rum_tx_mgt is called only from rum_raw_xmit (:3065,
params==NULL legacy path) β ic_raw_xmit β ieee80211_raw_output β bpf
writes on the 802.11 interface. /dev/bpf is root-only on DragonFly β
privileged trigger β Low severity (local DoS of the interface, recoverable
by an admin down/up).
Why inconclusive on this guest
No RT2573 hardware β rum_raw_xmit cannot be entered. The logic is
modeled exactly (rum_txslot_leak.c); guest output confirms the wedge
arithmetic (7 injections β tx_nfree=1 β gate fails; down/up restores 8).
Fix
Move the pop to after the validation block (mirroring rum_tx_data's
ordering), fix.diff, git apply --check clean. Hardware-gated:
not_testable for kernel validation.
Kernel references
- sys/bus/u4b/wlan/if_rum.c:1478-1480 (pop before validation)
- sys/bus/u4b/wlan/if_rum.c:1487-1494 (orphaning returns)
- sys/bus/u4b/wlan/if_rum.c:1631-1645 (rum_tx_data does it right)
- sys/bus/u4b/wlan/if_rum.c:1734 (rum_start MINFREE gate)
- sys/bus/u4b/wlan/if_rum.c:2577, 787-804 (only recovery path)
- sys/bus/u4b/wlan/if_rumvar.h:29-30 (LIST_COUNT=8, MINFREE=2)
- sys/netproto/802_11/wlan/ieee80211_output.c:631-639 (caller frees m/ni)
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff (move the pop after validation) verified with 'git apply --check' against the pristine sys/ tree; kernel behavior not exercisable without RT2573 hardware. Hardware-gated: not_testable.
fix.diff (git-apply clean); VERDICT.md
Confirmed kernel references
- sys/bus/u4b/wlan/if_rum.c:1478
- sys/bus/u4b/wlan/if_rum.c:1490
- sys/bus/u4b/wlan/if_rum.c:1494
- sys/bus/u4b/wlan/if_rum.c:1631
- sys/bus/u4b/wlan/if_rum.c:1670
- sys/bus/u4b/wlan/if_rum.c:1734
- sys/bus/u4b/wlan/if_rum.c:3055
- sys/bus/u4b/wlan/if_rum.c:2577
- sys/bus/u4b/wlan/if_rumvar.h:29
- sys/netproto/802_11/wlan/ieee80211_output.c:631
Detail
Exploit chain
root: 7x bpf-injected Protected-flag mgmt frames with no key -> tx_nfree 8->1 -> rum_start/rum_raw_xmit gates fail -> interface TX wedged until admin down/up (availability only, no memory-safety impact)
Evidence (decisive lines)
run.log: 'injected 16 ... orphaned slots=16; tx_nfree=1 / TX path wedged after 7 injections / after ifconfig down/up: tx_nfree=8'; rum_txslot_leak.c models :1478-1480, :1490, :1734 and the :2577 recovery exactly
PoC changes
No seed; exact state-machine model of the pop/error/gate/recovery logic
Verified recommended fix
In rum_tx_mgt(), take the tx_free slot only after the PROTECTED/key validation block (mirror rum_tx_data's ordering)
Verdict
Deterministic driver-logic defect, provable from source without hardware. rum_tx_mgt() pops the tx_free head and decrements tx_nfree (if_rum.c:1478-1480) BEFORE validating the frame; the ENOENT (:1490, Protected mgmt frame with no tx key) and ENOBUFS (:1494, SWCRYPT ic_encap failure) returns orphan the popped entry permanently - it is on no list, holds no mbuf, and tx_nfree is never restored. RUM_TX_LIST_COUNT=8 / RUM_TX_MINFREE=2 (if_rumvar.h:29-30): seven such errors wedge the TX path (rum_start gate :1734 and rum_raw_xmit gate :3055 both fail), recoverable only via rum_init->rum_setup_tx_list (:2577), i.e. ifconfig down/up. Sibling rum_tx_data() performs the same key checks BEFORE its pop (:1631-1645 vs pop at :1670) and frees the mbuf on error - the pop-before-validate ordering is unique to rum_tx_mgt. Trigger is privileged (raw 802.11 injection via bpf on the wlan interface; /dev/bpf is root-only), the caller ieee80211_raw_output (ieee80211_output.c:631-639) correctly frees mbuf+node on error, so impact is a local, privileged, recoverable TX-path DoS => Low severity. Hardware-gated in-kernel (no RT2573 on the guest); the exact state machine was modeled and run on the guest: wedge after exactly 7 injections, down/up restores tx_nfree=8.
No comments yet.