# 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:

```c
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`; no `wlan_*` modules loaded.
- `wlan_rssadapt` is `optional wlan_rssadapt` (`sys/conf/files:1655`), **not**
  in the default `X86_64_GENERIC` kernel.
- 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_complete` live. 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 reproducing
  `rssadapt_tx_complete`; instruments the line-327 deref. `-DFIX_NULL_CHECK`
  adds 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-check `arg1`/`arg2`, return early.
- `VERDICT.md` — full narrative + mechanism + citations.
- `build.log` / `run.log` — baseline (buggy) build+run on the unpatched `#0`.
- `fix_build.log` — full `make -j6 nativekernel` log for the single-fix kernel.
- `fix_run.log` — harness run on the patched `#1` kernel (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`, sha256
  `c5e894d9…`) the source-level guard is present and the wlan_rssadapt module
  compiles cleanly with `-Werror`.
