DF-3429 / verdict.json
{ "finding_id": "DF-3429", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "DWDS discovery frames staged on ic->ic_stageq by ieee80211_dwds_discover (ieee80211_wds.c:333-337, gated only by station authorization at ieee80211_hostap.c:654-667) are removed-and-returned by ieee80211_ageq_age() when their TTL expires, but ieee80211_node_timeout() calls it as a bare statement (ieee80211_node.c:2255) and drops the returned mbuf list on the floor: every unserviced discovery frame permanently leaks its mbuf + 2KB cluster. Sustained 4-addr traffic from an associated station = sustained kernel heap exhaustion (remote DoS). Runtime verification is hardware-gated: the QEMU audit guest has no 802.11 radio (kldload if_iwm/if_run attach nothing, zero wireless PCI devices - wlan_gate.txt), so no ieee80211com exists to exercise the path; mechanics are certain from source and the identical bare call exists in FreeBSD HEAD (ieee80211_node.c:2568), i.e. the defect is inherited from upstream.", "exploit_chain": "associate to AP vap (open/PSK) -> send 4-addr data frames (no WDS vap plumbed) -> frames stage on ic_stageq with ~40s TTL -> ageq_age expires them -> list leaked -> repeat at rate R leaks ~R*2KB/s until OOM/panic.", "evidence": "VERDICT.md (path:line chain + upstream comparison); trigger_stageq_leak.c (annotated); wlan_gate.txt (hardware gate on guest); fix.diff", "kernel_refs": [ "sys/netproto/802_11/wlan/ieee80211_wds.c:321", "sys/netproto/802_11/wlan/ieee80211_wds.c:335", "sys/netproto/802_11/wlan/ieee80211_node.c:2255", "sys/netproto/802_11/wlan/ieee80211_ageq.c:162", "sys/netproto/802_11/wlan/ieee80211_ageq.c:87", "sys/netproto/802_11/wlan/ieee80211_hostap.c:654" ], "poc_changes": "No seed; authored annotated trigger. Guest attempt limited to proving the hardware gate (no radio => no wlan vaps).", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 18, "guest_dirty": 1, "build_cmd": "n/a (kernel-side defect; no userland build)", "run_cmd": "./run.sh (documents the QEMU hardware gate: kldload if_iwm/if_run attach no device; ifconfig -C lacks a wlandev)", "code_hash": "a954202997de8ad8fafd16e91859553c349ca53f6d05e9e2e0f7b98d51318de0", "notes": "Sink lives in ieee80211_node.c but the reachable producer and the DWDS semantics are in ieee80211_wds.c (this files audit). Not DF-0618 (that is the age KASSERT overflow in the same expression); this is the leak at expiry. Upstream FreeBSD identical - coordinate disclosure.", "recommended_fix": "Capture and free the list returned by ieee80211_ageq_age() in ieee80211_node_timeout (ieee80211_ageq_mfree); see fix.diff.", "fix_status": "not_testable", "fix_kernel_uname": "", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against ieee80211_node.c (consume the returned list); cannot be validated on the QEMU guest - no 802.11 hardware, so neither baseline nor patched behavior is exercisable.", "fix_evidence": "fix.diff; wlan_gate.txt" } |