# DF-3327 VERDICT — REPRODUCED (remote kernel panic, single HWMP PREQ action frame)

## Runs

| run | kernel | input | result |
|-----|--------|-------|--------|
| baseline | stock `X86_64_GENERIC #0` (INVARIANTS), clean `with-src` snapshot | step 4 (peering dance) + **one** step-30 PREQ | `panic: null node`, backtrace `hwmp_send_action → hwmp_recv_action_meshpath → mesh_recv_mgmt → mesh_input → ieee80211_input_mimo`, guest wedged in ddb (`panic.txt`, `run.log`/console) |
| fixed | `#1` with `fix.diff` (NULL check in `hwmp_send_action`) | same, step 30 fired **twice** | no panic, `NO_PANIC_HERE` / `STILL_UP_AFTER_SECOND_PREQ` printed, RC=0, guest up; PREQ still fully processed (forwarded broadcast PREQ in txlog, `fix_run.log`) |

## Why it reproduces (path:line)

1. `ieee80211_action.c:243-256` — CAT_MESH action frames dispatch once the
   attacker link is ESTABLISHED (auto-peered via the fwm dance; no user auth
   on default open mesh).
2. `ieee80211_hwmp.c:417-474` — the PREQ IE (len=37, tcount=1) parses
   cleanly; `verify_mesh_preq_len` passes (`:328`).
3. `ieee80211_hwmp.c:1055-1079` — `rt_add(orig 02:00:00:00:e0:01)` →
   M_ZERO route (`ieee80211_mesh.c:203-215`): INVALID, nexthop 0, metric 0,
   `hr_seq` 0.
4. `ieee80211_hwmp.c:1089-1102` — `origseq=0` is neither GT the stored 0 nor
   (equal-seq ∧) better-metric ⇒ **no update, route stays INVALID**.
   `:1103-1106` — neither discard clause fires (no target route, originator
   route not VALID) ⇒ processing continues.
5. `:1216-1242` — target is broadcast + TO bit ⇒ proactive branch;
   `(rt_flags & VALID) == 0` ⇒ "reply with PREP" ⇒ `:1254`
   `hwmp_send_prep(vap, rtorig->rt_nexthop /* 00:00:00:00:00:00 */, &prep)`.
6. `ieee80211_hwmp.c:627` — `ieee80211_mesh_find_txnode(vap, 00:…:00)` →
   no route for the zero MAC ⇒ NULL (`ieee80211_mesh.c:1030-1033`).
7. `ieee80211_hwmp.c:636` — `KASSERT(ni != NULL, ("null node"))` ⇒
   **panic** (stock INVARIANTS kernel). On production kernels `:637`
   `ic = ni->ni_ic` is a NULL-page deref ⇒ fatal fault either way.

Same sink, two more remote routes: PREP propagation
(`ieee80211_hwmp.c:1521-1558`, `rtorig` exists-but-invalid) and the
intermediate PREP reply (`:1271-1303`).

## Impact

Remote (adjacent, unauthenticated after auto-peering) kernel panic of any
default-config mesh node, one frame per panic, repeatable at will. Not a
memory-corruption primitive (NULL deref), so DoS is the ceiling.

## Fix validation

`fix.diff` (NULL check + drop + ENOENT in `hwmp_send_action`) — applied in
guest `/usr/src`, `make -j6 nativekernel KERNCONF=X86_64_GENERIC` (0 errors),
`make installkernel`, reboot, same PoC twice: **panic gone, guest healthy,
PREQ still forwarded** (behavior preserved). Baseline vs patched transcript
in `run.log` / `fix_run.log`.

## Notes

- The panic occurred *inside* the `sysctl kern.fwm_step=30` write (synchronous
  RX injection), matching the `ieee80211_input_mimo` frames in the backtrace.
- Guest reset to clean `with-src` snapshot after both runs.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
