# DF-0587 — PoC: race scan_curchan_task against concurrent vap detach

Privileged local race (root required: vap destroy). Drives
`scan_curchan_task`'s unlock/re-lock window against a concurrent vap detach so
that `ss->ss_vap` / `ss->ss_ops` get nulled by `ieee80211_scan_vdetach` while
the task is unlocked inside `ic_set_channel`, producing a NULL-vap page fault
on re-lock.

## Files

- `race.c` — minimal reproducer (4 scan-request threads + 4 vap-destroy threads).
- (added by per-PoC verifier) `build.sh`, `run.sh`, `build.log`, `run.log`,
  `VERDICT.md`, `manifest.json`.

## Build & run

```
cc -O2 -Wall race.c -o race
sudo ./race wlan0
```

## Expected first outcome

Kernel panic (`Fatal trap 12: page fault while in kernel mode`) with the
faulting instruction inside `scan_done` (`vap->iv_flags_ext` deref at
sys/netproto/802_11/wlan/ieee80211_scan_sw.c:916) on non-DEBUG kernels, or
inside `IEEE80211_DPRINTF(ss->ss_vap,…)` at :700 / :724 / :775 on DEBUG
kernels.

## Notes for the per-PoC verifier

- Requires root (`SIOCIFDESTROY` is privilege-gated). This is a privileged DoS
  / reliability bug, not an unprivileged-escalation bug.
- Requires a `wlan(4)` vap with a driver loaded; verify with `ifconfig wlan0`
  and `dmesg | grep wlan`.
- The race fires during ordinary operational teardown — `wpa_supplicant` /
  `NetworkManager` restarts, system shutdown with active scan, driver reload
  all hit the same path; a reproduced panic is the success criterion.
- If destroy toggles the vap faster than the scan can arm, try inserting a
  short `usleep` between scan-request and destroy to widen the channel-change
  window. The race is fundamentally an unlocked `ic_set_channel` sleep, so
  any driver with a non-trivial set_channel path is a reliable target.
