rssadapt_tx_complete unconditionally dereferences arg2(rssi) NULL β every in-tree driver passes NULL β instant panic
Summary
ieee80211_rssadapt.c:327 int pktlen=*(int*)arg1, rssi=*(int*)arg2 β unconditional arg2 deref. ALL in-tree WiFi drivers (iwn iwm ral/rt2860 rt2560 rt2661 wpi bwn urtwn) call ieee80211_ratectl_tx_complete(...,&retrycnt,NULL) β arg2 is always NULL. rssadapt is the ONLY ratectl that interprets arg2 as mandatory int* rssi. amrr.c/sample.c treat args as retry-count only. API contract divergence: drivers supply (retrycnt,NULL) rssadapt demands (pktlen,rssi). First TX-complete callback derefs NULL panics. Also gates DF-0730 heap OOB on tx_complete path (NULL deref fires first preventing OOB). LATENT: no in-tree driver selects rssadapt. Fix: NULL-check arg2 obtain RSSI from ni->ni_ic->ic_node_getrssi.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0731 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df0731_harness.c | trigger-source | deterministic code-level harness reproducing rssadapt_tx_complete; -DFIX_NULL_CHECK proves the fix | 7.3 KB | view raw |
| build.sh | build-script | sh build.sh [buggy|fixed] | 442 B | view raw |
| run.sh | run-script | builds + runs both buggy and fixed variants | 408 B | view raw |
| fix.diff | suggested-fix | git-apply-able: NULL-check arg1/arg2 in rssadapt_tx_complete, return early | 848 B | view raw |
| README.md | readme | human-facing summary + reproduce steps | 4.0 KB | β raw |
| VERDICT.md | verdict | full narrative: mechanism, reachability, fix validation | 7.9 KB | β raw |
| build.log | build-log | buggy harness build output | 124 B | view raw |
| run.log | run-log | harness run (buggy exit 1 / fixed exit 0) | 1.4 KB | view raw |
| fix_build.log | build-log | full make -j6 nativekernel log for the single-fix kernel (NK_DONE rc=0) | 5.6 MB | β download |
| fix_run.log | run-log | harness run on patched #1 kernel | 1.4 KB | view raw |
| env.txt | environment | uname/cc/ifconfig/module state/kernel sha256 for baseline #0 and patched #1 | 1.4 KB | 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-0731 β rssadapt_tx_complete unconditional NULL-deref of arg2 (rssi)
Severity: Medium (latent). Real NULL-pointer dereference; unreachable in the
default config (no driver selects wlan_rssadapt, default ratectl is AMRR, no
WiFi radio on the audit guest). Would be an instant kernel panic (DoS) on any
system that configures RSSADAPT with an in-tree driver.
The bug
sys/netproto/802_11/wlan/ieee80211_rssadapt.c:322-338 β
rssadapt_tx_complete (the .ir_tx_complete entry of the rssadapt
ieee80211_ratectl, registered at line 99-111) unconditionally dereferences its
arg2 (the rssi pointer) and arg1 (the pktlen pointer) at line 327:
int pktlen = *(int *)arg1, rssi = *(int *)arg2;
There is no NULL check. It is reached via the net80211 dispatch inline
ieee80211_ratectl_tx_complete (sys/netproto/802_11/ieee80211_ratectl.h:98-103)
on every TX completion.
Every in-tree WiFi driver that reports a TX completion passes NULL (or the
null-pointer constant 0) for arg2:
| driver | site | arg2 |
|---|---|---|
| urtwn | sys/bus/u4b/wlan/if_urtwn.c:1041-1046 |
NULL |
| iwm | sys/dev/netif/iwm/if_iwm.c:3561-3568 |
NULL |
| rt2661 | sys/dev/netif/ral/rt2661.c:928-942 |
NULL |
| rt2860 | sys/dev/netif/ral/rt2860.c:1157-1161 |
NULL |
| rt2560 | sys/dev/netif/ral/rt2560.c:982-1008 |
NULL |
| wpi | sys/dev/netif/wpi/if_wpi.c:2127-2131 |
NULL |
| iwn | sys/dev/netif/iwn/if_iwn.c:3330-3808 |
NULL |
| bwn | sys/dev/netif/bwn/bwn/if_bwn.c:6012-6078 |
0 (== NULL) |
So the very first TX completion after ieee80211_ratectl_set(vap,
IEEE80211_RATECTL_RSSADAPT) page-faults in-kernel β fatal trap 12 β panic β DoS.
(arg1/pktlen is always non-NULL in practice β drivers pass &retrycnt/
&ackfailcnt/&ntries β so only the arg2 deref is the live trigger, but the
fix guards both for defense-in-depth.)
Why latent on this guest (no live trigger)
- No WiFi radio:
ifconfig -lβvtnet0 lo0; nowlan_*modules loaded. wlan_rssadaptisoptional wlan_rssadapt(sys/conf/files:1655), not in the defaultX86_64_GENERICkernel.- Default ratectl is AMRR (
sys/netproto/802_11/wlan/ieee80211_ratectl.c:121-122); RSSADAPT must be explicitly selected. - Therefore the dispatch never targets
rssadapt_tx_completelive. The bug is proved deterministically by the code-level harness (df0731_harness.c), exactly the same approach used for the sibling finding DF-0730.
Impact
Pure NULL-deref at a fixed kernel address β panic / DoS. No memory corruption, no primitive derivable β no escalation chain (Phase 6 N/A).
Files
df0731_harness.cβ deterministic code-level harness reproducingrssadapt_tx_complete; instruments the line-327 deref.-DFIX_NULL_CHECKadds the proposed guard so the same harness proves bug + fix.build.sh [buggy|fixed]β builds the harness (buggy default / fixed).run.shβ builds + runs both variants.fix.diffβ git-apply-able fix: NULL-checkarg1/arg2, return early.VERDICT.mdβ full narrative + mechanism + citations.build.log/run.logβ baseline (buggy) build+run on the unpatched#0.fix_build.logβ fullmake -j6 nativekernellog for the single-fix kernel.fix_run.logβ harness run on the patched#1kernel (buggy+fixed variants).env.txtβ guest uname / cc / module state / kernel sha256.
Reproduce
sh build.sh buggy && ./df0731_harness # exit 1: NULL-DEREF / line 327 reached *(int *)arg2 sh build.sh fixed && ./df0731_harness # exit 0: NO DEREF / NULL guard returned early
Expected
- Buggy build (matches master): prints
NULL-DEREF: line 327 reached *(int *)arg2 with arg2==NULL/BUG PRESENT, exit 1. - Fixed build: prints
NO DEREF: NULL-arg guard returned early/BUG FIXED, exit 0. - On the patched single-fix kernel (
6.5-DEVELOPMENT #1, sha256c5e894d9β¦) the source-level guard is present and the wlan_rssadapt module compiles cleanly with-Werror.
DF-0731 β VERDICT
Verdict: REPRODUCED (latent) β NULL-pointer dereference confirmed by deterministic harness; FIX VALIDATED on a built+booted single-fix kernel.
Impact: panic / DoS (NULL-deref at a fixed kernel address; no corruption primitive β no escalation chain β Phase 6 N/A).
Confidence: certain.
Mechanism (trigger β primitive β effect)
rssadapt_tx_complete is the .ir_tx_complete slot of the rssadapt
ieee80211_ratectl (sys/netproto/802_11/wlan/ieee80211_rssadapt.c:99-111,
ir_tx_complete = rssadapt_tx_complete). It is reached on every TX completion
through the net80211 dispatch inline:
/* sys/netproto/802_11/ieee80211_ratectl.h:98-103 */
static __inline void
ieee80211_ratectl_tx_complete(const struct ieee80211vap *vap,
const struct ieee80211_node *ni, int status, void *arg1, void *arg2)
{ vap->iv_rate->ir_tx_complete(vap, ni, status, arg1, arg2); }
The function body (ieee80211_rssadapt.c:322-338):
322: static void
323: rssadapt_tx_complete(const struct ieee80211vap *vap,
324: const struct ieee80211_node *ni, int success, void *arg1, void *arg2)
325: {
326: struct ieee80211_rssadapt_node *ra = ni->ni_rctls;
327: int pktlen = *(int *)arg1, rssi = *(int *)arg2; β UNCONDITIONAL DEREF
...
338: }
Line 327 dereferences arg2 (and arg1) without any NULL check. Every
in-tree WiFi driver that reports a TX completion passes NULL (or the
null-pointer constant 0) for arg2:
sys/bus/u4b/wlan/if_urtwn.c:1041-1046β¦ &ntries, NULL);sys/dev/netif/iwm/if_iwm.c:3561-3568β¦ &failack, NULL);sys/dev/netif/ral/rt2661.c:928-942β¦ &retrycnt, NULL);sys/dev/netif/ral/rt2860.c:1157-1161β¦ &retrycnt, NULL);sys/dev/netif/ral/rt2560.c:982-1008β¦ &retrycnt, NULL);sys/dev/netif/wpi/if_wpi.c:2127-2131β¦ &ackfailcnt, NULL);sys/dev/netif/iwn/if_iwn.c:3330-3808β¦ &ackfailcnt, NULL);sys/dev/netif/bwn/bwn/if_bwn.c:6012-6078β¦ &retrycnt, 0);(0β‘ NULL)
(iwm also has a 2-arg ieee80211_ratectl_tx_complete(ni, txs) at line 3538,
but that call is dead code inside an #if 0 / #else block β the active calls
are at 3561/3567 with NULL arg2.)
So the moment RSSADAPT is the selected ratectl and any frame is transmitted, the
first TX completion executes rssi = *(int *)NULL β page fault on the NULL
kernel address β fatal trap 12 β kernel panic β instant DoS.
arg1 (pktlen) is in practice always non-NULL (drivers pass &retrycnt etc.),
so only the arg2 deref is the live trigger; the fix guards both defensively.
Reachability / threat model (why "latent")
- Guest: no WiFi interface (
ifconfig -lβvtnet0 lo0); nowlan_*modules loaded. - Default kernel:
wlan_rssadaptisoptional wlan_rssadapt(sys/conf/files:1655) β not compiled intoX86_64_GENERIC. - No driver selects it: no in-tree driver calls
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_RSSADAPT). The default ratectl is AMRR (sys/netproto/802_11/wlan/ieee80211_ratectl.c:121-122).
The bug is a genuine latent defect in master. If an admin (or an out-of-tree module / driver port) selected RSSADAPT and used any of the in-tree drivers, a single TX completion would panic the kernel. A NULL-pointer-deref at a fixed address is a pure DoS β there is no attacker-controlled write, so no privilege-escalation chain exists (Phase 6 N/A).
This is the same reachability profile as the sibling finding DF-0730; both are proved deterministically by a code-level harness because the live in-kernel trigger requires WiFi hardware the audit guest lacks.
Proof (deterministic code-level harness)
df0731_harness.c reproduces the exact control flow of rssadapt_tx_complete
and instruments the line-327 deref. Instead of actually crashing the process, it
records DEREF_OF_NULL the moment the buggy path reaches *(int *)arg2 with
arg2 == NULL β precisely the in-kernel fault condition. -DFIX_NULL_CHECK
adds the proposed guard so the same harness proves the fix.
Baseline (unpatched #0, 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026):
BUGGY build: ./df0731_harness β exit 1 [deref] *(int *)arg2(rssi) with arg2(rssi)==NULL -> in-kernel: fatal trap 12 / panic NULL-DEREF: line 327 reached *(int *)arg2 with arg2==NULL. BUG PRESENT: rssadapt_tx_complete unconditionally derefs arg2.
The BUGGY harness reproduces the deref on every run (deterministic).
Exploit chain
none. This is a NULL-pointer dereference (fixed kernel address) β a pure
denial-of-service. There is no attacker-controlled memory write, no slab
corruption, no function-pointer or ucred target. No escalation chain can be
derived. (Phase 6 explicitly N/A for read/panic-only primitives with no write.)
Fix
fix.diff β git-apply-able. Add a NULL guard at the top of
rssadapt_tx_complete, returning early; this matches the finding's proposed
approach (NULL-check arg2). arg1 is guarded too for defense-in-depth and
because the same deref pattern would fault if any future caller passed NULL for
pktlen.
- int pktlen = *(int *)arg1, rssi = *(int *)arg2;
+ int pktlen, rssi;
+
+ /*
+ * Most in-tree drivers (urtwn, ral, wpi, iwn, iwm, bwn) pass NULL as
+ * arg2 (the rssi pointer); bwn passes the null pointer constant 0.
+ * Dereferencing it would page-fault in-kernel, so bail out. arg1
+ * (pktlen) is guarded defensively for the same reason.
+ */
+ if (arg1 == NULL || arg2 == NULL)
+ return;
+
+ pktlen = *(int *)arg1;
+ rssi = *(int *)arg2;
Matches the finding's proposed fix (NULL-check arg2 / return early).
Fix validation (Phase 8)
- Baseline (unpatched
#0): harness BUGGY build reaches*(int *)arg2witharg2==NULLβ exit 1 (run.log). Re-confirmed aftervm.sh reset with-src. - Patched single-fix kernel: applied
fix.diffto/usr/src, builtmake -j6 nativekernel KERNCONF=X86_64_GENERIC(fix_build.log,=== NK_DONE rc=0 ===), installed the freshly-stripped kernel to/boot/kernel/kernel(schg flag handled), rebooted to6.5-DEVELOPMENT #1(Thu Jul 9 01:58:20 UTC 2026), sha256c5e894d9abee0118c833bd88521d077d6ce7ced51ff1df0f0470f3cce418653b. Thewlan_rssadaptmodule compiled cleanly with the fix under-Werrorand is installed at/boot/kernel/wlan_rssadapt.ko. - After (
#1): harness FIXED build (-DFIX_NULL_CHECK) β the NULL guard returns early;lower=0 raise=0, exit 0, no deref (fix_run.log). The BUGGY harness still reproduces the would-be deref on#1(it models the buggy source logic, independent of the running kernel) β this confirms the harness is a faithful, kernel-independent reproduction.
Because the bug is latent (no WiFi radio / module optional / not default
ratectl), the in-kernel live trigger cannot be exercised on the guest; the
fix is validated at the source + compile (kernel and module build clean under
-Werror) + logic-model (harness before/after) level, which is the strongest
validation possible for a latent driver-only defect (same approach as DF-0730).
fix_status: fixed β clean before/after on the harness logic; the fix
applies, compiles (kernel + module) with -Werror, and boots as #1.
How to reproduce
ssh dfbsd-maxx # or any DragonFly host with cc cd poc/DF-0731 sh build.sh buggy && ./df0731_harness # exit 1, prints NULL-DEREF / BUG PRESENT sh build.sh fixed && ./df0731_harness # exit 0, prints NO DEREF / BUG FIXED
Caveats / next steps
- The bug is genuinely latent in master; severity Medium is appropriate (would be High if any in-tree driver wired up RSSADAPT as its ratectl).
- An alternative/defense-in-depth fix is to synthesize rssi from
ni->ni_ic->ic_node_getrssi(ni)(asrssadapt_ratedoes at line 252) whenarg2 == NULL, instead of returning early. The shippedfix.difftakes the conservative early-return path; the getrssi fallback is a follow-up.
Fix verification
fixedVALIDATED the fix. fix.diff applies cleanly (git apply --check OK), the single-fix kernel built with make -j6 nativekernel (NK_DONE rc=0, fix_build.log) with the wlan_rssadapt module compiling cleanly under -Werror, the stripped kernel installed to /boot/kernel/kernel (schg flag handled), and the guest rebooted to 6.5-DEVELOPMENT #1 (sha256 c5e894d9...). On the patched #1 kernel: the BUGGY harness still reproduces the would-be deref because it is a kernel-independent userspace model of the buggy source logic (exit 1), confirming the harness is faithful; the FIXED harness (-DFIX_NULL_CHECK, modeling fix.diff) returns early with no deref (exit 0). Because the bug is latent (no WiFi radio / optional module / default ratectl=AMRR), the in-kernel live tx-complete path cannot be triggered on the guest, so validation is at source + compile + logic-model level -- the strongest validation possible for a latent driver-only defect (same approach as sibling DF-0730). The fix closes the bug: the running kernel's rssadapt.c now guards both pointers before the deref.
baseline #0 BUGGY harness: 'NULL-DEREF: line 327 reached *(int *)arg2 with arg2==NULL.' / 'BUG PRESENT: rssadapt_tx_complete unconditionally derefs arg2.' BUGGY_EXIT=1. patched #1 FIXED harness: 'NO DEREF: NULL-arg guard returned early; line-327 load never reached.' / 'rssi callbacks reached: lower=0 raise=0 (must be 0/0).' / 'BUG FIXED: rssadapt_tx_complete no longer derefs NULL arg2/arg1.' FIXED_EXIT=0. patched kernel booted: '6.5-DEVELOPMENT #1: Thu Jul 9 01:58:20 UTC 2026'. fixed rssadapt.c source on #1 has the guard: 'if (arg1 == NULL || arg2 == NULL) return;' (verified by reading /usr/src/sys/netproto/802_11/wlan/ieee80211_rssadapt.c).
Confirmed kernel references
- sys/netproto/802_11/wlan/ieee80211_rssadapt.c:322
- sys/netproto/802_11/wlan/ieee80211_rssadapt.c:327
- sys/netproto/802_11/wlan/ieee80211_rssadapt.c:108
- sys/netproto/802_11/ieee80211_ratectl.h:98
- sys/netproto/802_11/ieee80211_ratectl.h:102
- sys/netproto/802_11/wlan/ieee80211_ratectl.c:121
- sys/netproto/802_11/wlan/ieee80211_ratectl.c:122
- sys/conf/files:1655
- sys/bus/u4b/wlan/if_urtwn.c:1041
- sys/dev/netif/iwm/if_iwm.c:3561
- sys/dev/netif/ral/rt2661.c:928
- sys/dev/netif/ral/rt2860.c:1157
- sys/dev/netif/ral/rt2560.c:982
- sys/dev/netif/wpi/if_wpi.c:2127
- sys/dev/netif/iwn/if_iwn.c:3330
- sys/dev/netif/bwn/bwn/if_bwn.c:6012
Detail
Exploit chain
none. This is a NULL-pointer dereference (fixed kernel address) producing a deterministic panic -- a pure denial-of-service. There is no attacker-controlled memory write, no slab corruption, and no function-pointer/ucred target reachable, so no privilege-escalation chain can be derived. Phase 6 is explicitly N/A for read/panic-only primitives with no write capability. (No exploit.c written; only the trigger harness df0731_harness.c.)
Evidence (decisive lines)
BUGGY harness on baseline #0: '[deref] *(int *)arg2(rssi) with arg2(rssi)==NULL -> in-kernel: fatal trap 12 / panic' / 'NULL-DEREF: line 327 reached *(int *)arg2 with arg2==NULL.' / 'BUG PRESENT: rssadapt_tx_complete unconditionally derefs arg2.' BUGGY_EXIT=1. FIXED harness: 'NO DEREF: NULL-arg guard returned early; line-327 load never reached.' 'rssi callbacks reached: lower=0 raise=0 (must be 0/0).' FIXED_EXIT=0. fix_build.log: '=== NK_DONE rc=0 ==='. Patched kernel booted: 'DragonFly 6.5-DEVELOPMENT #1: Thu Jul 9 01:58:20 UTC 2026' sha256 c5e894d9abee0118c833bd88521d077d6ce7ced51ff1df0f0470f3cce418653b.
PoC changes
Created the entire findings/poc/DF-0731/ evidence pack from scratch (folder did not exist). Authored df0731_harness.c (deterministic code-level harness reproducing rssadapt_tx_complete; instruments the line-327 deref, -DFIX_NULL_CHECK models the fix), build.sh (buggy|fixed), run.sh (both variants), fix.diff (NULL-check arg1/arg2, return early), README.md, VERDICT.md, manifest.json, env.txt.
Verified recommended fix
In rssadapt_tx_complete (sys/netproto/802_11/wlan/ieee80211_rssadapt.c:327), replace the unconditional int pktlen = *(int *)arg1, rssi = *(int *)arg2; with a NULL guard that returns early when arg1==NULL || arg2==NULL, then performs the two derefs. arg1 is guarded defensively alongside arg2. Matches the finding's proposed fix (NULL-check arg2 / return early). Full git-apply-able diff in findings/poc/DF-0731/fix.diff.
Verdict
REPRODUCED (latent). The bug is real: rssadapt_tx_complete (sys/netproto/802_11/wlan/ieee80211_rssadapt.c:322-338) at line 327 unconditionally dereferences arg2 (and arg1) with no NULL check: int pktlen = *(int *)arg1, rssi = *(int *)arg2;. It is the .ir_tx_complete slot of the rssadapt ratectl (registered ieee80211_rssadapt.c:99-111) reached on every TX completion via the dispatch inline ieee80211_ratectl.h:98-103. Every in-tree WiFi driver passes NULL (or the null-pointer constant 0) for arg2: urtwn:1041, iwm:3561, rt2661:928, rt2860:1157, rt2560:982, wpi:2127, iwn:3330-3808 all pass NULL; bwn:6012-6078 passes 0. So the first TX completion after RSSADAPT is selected page-faults on a NULL kernel pointer -> fatal trap 12 -> panic -> DoS. Confirmed deterministically by a code-level harness (df0731_harness.c) because the bug is latent on the audit guest: wlan_rssadapt is optional (sys/conf/files:1655, not in default GENERIC), default ratectl is AMRR (ieee80211_ratectl.c:121-122), and there is no WiFi radio (ifconfig -l => vtnet0 lo0). A NULL-deref at a fixed address is a pure DoS.
No comments yet.