# DF-5249 — lockless `run_cmdq` producer/consumer machinery races

`sys/bus/u4b/wlan/if_run.c`

## What

The 16-slot deferred-command ring `sc->cmdq[]` is filled by producers
**under no lock at all** (`run_key_set` 2368-2375, `run_key_delete`
2443-2453, `run_newassoc` 2669-2675, `run_update_beacon` 4894-4898,
`run_updateprot` 4960-4964, `run_updateslot` 5206-5210,
`run_tx` FIFO-drain 3425-3429, tx-timeout 3157-3161), each storing
`.func` **first** and the argument fields after, then
`ieee80211_runtask()`. The single consumer `run_cmdq_cb()` (1041-1068)
executes slots under `RUN_LOCK` with `pending` = taskqueue coalesced
count and `cmdq_exec` walking the ring.

Three failure modes:

1. **Torn slot**: consumer sees `.func != NULL` before the producer's
   `.arg0/.arg1/.k/.mac` stores land → `func(NULL)`; for
   `run_update_beacon_cb` that is an immediate NULL dereference
   (`vap = arg; ni = vap->iv_bss`).
2. **Identity mismatch after wrap**: `RUN_CMDQ_GET` wraps at 16
   outstanding commands; a slot is overwritten between the consumer's
   `.func` and `.arg0` loads (or before it runs) → `func_new(arg0_old)`:
   e.g. `run_key_set_cb` invoked with a `vap` pointer as
   `struct run_cmdq *` → `cmdq->k` loaded from vap memory → wild
   pointer dereference (type confusion).
3. **Lost commands**: wrap overwrites a not-yet-executed entry — a lost
   `run_key_delete` leaves a stale hardware key installed (data
   remains decryptable/usable after hostapd believes it removed it).

## Repro (simulated; hardware-gated)

`cmdq_race.c` models the ring, `RUN_CMDQ_GET`, producer store order and
the exact `run_cmdq_cb` consumer loop with coalesced pending counts.
Guest results (3 runs, 10 s):

    executed callbacks   : ~61-62M
    torn NULL-arg calls  : 12,011-13,347
    identity mismatches  : 470k-485k
    slot wrap overwrites : ~53M

Rates are inflated by the harness's deliberate consumer lag, but every
counter demonstrates the corresponding interleaving is reachable the
moment the task thread is delayed (preemption, the 2.5 s
`run_do_request` retries of DF-5248, or >16 deferred commands in flight
— beacon TIM churn + key updates + tx-timeouts during a scan).

## Verdict

`inconclusive` (in-kernel repro needs real run(4) hardware), confidence
`likely` (reachability proven by simulation; store/execute order taken
verbatim from the source).
