# DF-3326 — VERDICT

**Status: reproduced** (baseline, stock INVARIANTS kernel #0 Thu Jul 2
06:02:54 UTC 2026) · impact: association (AID, power-save, EAPOL
pass-through, assoc-flood DoS) granted without any completed
authentication · fix: validated (kernel #1 21:29 with DF-3323+DF-3326
fixes).

## Root cause (path:line)

- `sys/netproto/802_11/wlan/ieee80211_hostap.c:1953-1962` — the ASSOC_REQ
  "not authenticated" gate tests only `ni == vap->iv_bss` (node-table
  existence).
- `sys/netproto/802_11/wlan/ieee80211_hostap.c:1072-1083` —
  `hostap_auth_shared()` creates the node (`ieee80211_dup_bss`) upon a
  seq-1 REQUEST, i.e. before the shared-key exchange completes (or fails).
  `hostap_auth_open()` does the same at `:947-950` (harmless there: open
  auth is by definition complete on request).
- Nothing between node creation and `ieee80211_node_join()`
  (`:2169`, node.c `:2524`) checks that authentication completed. For
  shared-key mode `ieee80211_node_is_authorized()` is only set by a
  successful seq-3 (`:1149`) — which the assoc path never consults.

The same shape exists for AUTH_AUTO (`hostap_auth_shared` accepts AUTO
nodes at `:1023-1024`). For 802.1x/WPA, association-before-auth is the
designed flow (auth deferred to EAPOL/4-way), so the correct predicate is
authmode-dependent (see fix).

## Reproduction (fw4 software radio, guest stock kernel)

- Control: `fw4_attack=4` with no node in the table → AP transmits
  **DEAUTH (subtype 0xc0)** — the intended "not authenticated" refusal
  exists in the code and is reached when `ni == iv_bss`.
- Attack: `fw4_attack=1` — one 30-byte AUTH(shared, seq1) REQUEST; node
  created, `AUTHORIZED=0`. `fw4_attack=4` — ASSOC_REQ; AP transmits
  **ASSOC_RESP (subtype 0x10)**, node gains `associd 0xc001` while
  `AUTHORIZED=0`; `ifconfig wlan0 list sta` shows AID 1 with no `A` flag
  (compare DF-3323 baseline: authorized bypass shows `A`).
- Found while validating the DF-3323 fix: on the DF-3323-patched kernel
  the cleartext seq-3 was correctly dropped, yet the follow-on ASSOC_REQ
  still returned `associd 0xc001` — a fully independent second bypass.

## Impact

- Unauthenticated station occupies the AID space (default
  `iv_max_aid` 128): 2 frames per fake station → cheap remote
  association-flood DoS until the inactivity timer reaps them.
- Appears associated to userland (`list sta`), eligible for the power-save
  queue, and — because the data path's unauthorized-port filter passes
  PAE frames (`:776`) — can inject EAPOL into the AP's network stack /
  bridge.
- Not authorized: non-PAE data still blocked at `:767` (and by DROPUNENC
  when set) — this is the complement of DF-3323, which gained
  authorization itself.

## Fix validation (kernel #1 21:29, DF-3323+DF-3326 fixes applied)

`fix.diff` widens the gate to
`ni == vap->iv_bss || ((ni_authmode == SHARED || AUTO) && !authorized)`.

- baseline: attack=1 → attack=4 = ASSOC_RESP (0x10), associd 0xc001.
- patched: attack=1 → attack=4 = **DEAUTH (0xc0)**, associd stays 0x0.
- regression: open-authmode vap, open auth (attack=6) → AUTHORIZED=1 →
  ASSOC_REQ → associd 0xc001 (legit flow unbroken). 802.1x/WPA vap types
  are untouched by the predicate (auth deferred by design).

`fix_baseline_reproduced=1`, `fix_patched_reproduced=0` → fix_status=fixed.

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