# DF-3460 — rssadapt sysctl interval handler UAF across vap teardown

**File:** `sys/netproto/802_11/wlan/ieee80211_rssadapt.c`
**Verdict:** REPRODUCED (code-level harness; module latent on this guest — see DF-0730
reachability notes).
**Severity filed:** Low (latent) — the *amrr* twin of this pattern
(ieee80211_amrr.c:390-403, plus `SYSCTL_ADD_UINT` pointing directly into the freed
chunk) is the DEFAULT ratectl and would be reachable on any real WiFi system.

## What the bug is

Lifetime chain on this tree:

1. vap create → `ieee80211_ratectl_init()` (ieee80211_ratectl.c:119-135) →
   `rssadapt_init()` kmallocs `vap->iv_rs` AND registers the world-readable sysctl
   `net.wlan.N.rssadapt_rate_interval` (rssadapt_sysctlattach, :356-362).
2. vap destroy → every in-tree wifi driver's `*_vap_delete()` (e.g. if_iwm.c:6486-6493)
   calls `ieee80211_ratectl_deinit(vap)` → `rssadapt_deinit()` (:151-155) →
   `IEEE80211_FREE(vap->iv_rs)` — **`iv_rs` is not cleared**.
3. Only much later, `ieee80211_vap_detach()` → … → `ieee80211_sysctl_vdetach(vap)`
   (ieee80211.c:827 — the **last** vdetach, after ether_ifdetach, ieee80211_stop,
   task drains, node detach) removes the oid.

For the entire window between (2) and (3) the oid stays registered and world-readable,
and `rssadapt_sysctl_interval()` (:340-353) does

```c
struct ieee80211_rssadapt *rs = vap->iv_rs;   /* dangling */
int msecs = ticks_to_msecs(rs->interval);     /* UAF READ  */
... sysctl_handle_int(...)                    /* 4 bytes -> any user */
rssadapt_setinterval(vap, msecs);             /* UAF WRITE (root) */
```

* **Unprivileged read**: `sysctl net.wlan.N.rssadapt_rate_interval` during
  `ifconfig wlanN destroy` returns 4 bytes read out of a freed (and typically
  already-reused — kmalloc size-class reuse is cross-type in DFly) heap chunk →
  kernel-heap info-leak gadget.
* **Root write**: `sysctl -w` in the same window writes 4 controlled bytes into
  the freed/reused chunk.

## Reproduce

```
./build.sh          # buggy (as shipped)
./run.sh            # → RESULT: BUG REPRODUCED …
./build.sh fixed    # deinit NULLs iv_rs + handler guards
./run.sh            # → RESULT: FIXED — no UAF read/write
```

(Built -O0: at -O2 gcc CSEs the post-free load with the pre-free one — UB elision
the kernel does not perform across the real sysctl dispatch.)

## Fix validation

* `fix.diff` — `git apply`-clean; patched `wlan_rssadapt` module builds clean with
  full kernel `-Werror` CFLAGS (`fix_module_build.log`, rc=0).
* Harness `fixed` mode: handler refuses (ENXIO) during the window; no freed-chunk
  read or write.
