DF-3466 / verdict.json
{ "finding_id": "DF-3466", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "ieee80211_ageq_append stores caller ages relative to the head of the queue (ageq.c:114) and KASSERTs non-negativity (:116); the DWDS staging caller (wds.c:335) feeds it ages derived from the unvalidated association listen-interval (hostap.c:1966->2130), so an associated station on a DWDS/mesh AP makes the relative age negative and panics INVARIANTS kernels (panic: age -781 reproduced on the stock X86_64_GENERIC guest, backtrace ieee80211_ageq_append+0xc1). Production kernels merely expire the frame one sweep early (no memory unsafety), capping severity at Medium/DoS. fix.diff clamps the negative relative age to 0; rebuilt kernel #1 runs the identical PoC with no panic (rc=0, aq_len=2), validating the fix.", "exploit_chain": "", "evidence": [ "panic.txt: serial-console capture: panic: age -781 with ieee80211_ageq_append+0xc1 backtrace from kldload of ageqpoc.ko", "run.log: baseline session transcript (ssh session dies at kldload; panic on console)", "run.2.log: fix-validation run on kernel #1 with fix.diff applied: append #2 rc=0 aq_len=2, no panic, clean unload", "ageqpoc.c: KLD driving the ageq API with exactly the two ages one attacker station controls (listen-interval 2000 then 1)", "fix.diff: clamp of negative relative age at ieee80211_ageq.c:114-117 (git-apply clean against sys/)", "VERDICT.md: full narrative incl. reachability chain hostap.c:1966 -> :2130 -> wds.c:335 -> ageq.c:114/116" ], "kernel_refs": [ "sys/netproto/802_11/wlan/ieee80211_ageq.c:114", "sys/netproto/802_11/wlan/ieee80211_ageq.c:116", "sys/netproto/802_11/wlan/ieee80211_wds.c:335", "sys/netproto/802_11/wlan/ieee80211_hostap.c:1966", "sys/netproto/802_11/wlan/ieee80211_hostap.c:2130", "sys/netproto/802_11/wlan/ieee80211_hwmp.c:2236", "sys/netproto/802_11/ieee80211_dragonfly.h:189" ], "poc_changes": "None versus the seed sketch concept; the PoC was authored fresh for this run: initial module missed the opt_wlan.h/opt_inet.h generation and the net/if_var.h include chain (mirrored ieee80211_ageq.cs own include order); ages chosen to mirror (ni_intval*ic_lintval<<2)/1024 exactly (2000*100*4/1024=781, 1*100*4/1024=0).", "attempts": 2, "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": 45, "guest_dirty": 0, "build_cmd": "cp Makefile.ageqpoc Makefile && make (guest /tmp/poc/DF-3466, bsd.kmod.mk, gcc 8.3)", "run_cmd": "kldload wlan; kldload ./ageqpoc.ko (root)", "code_hash": "9708414a22d3203074e70458a29cb98cfd40a5162da895478129438275560d30", "notes": "Impact ceiling is a controlled KASSERT panic on INVARIANTS kernels (remote RF-side DoS after association); no memory corruption, no escalation. Production kernels: early frame expiry only. Bonus hardening: validate assoc listen-interval (lintval) at hostap.c parse time. Guest left clean (vm.sh reset with-src after validation).", "recommended_fix": "Clamp negative relative age to 0 in ieee80211_ageq_append (see fix.diff); additionally validate the association listen-interval.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sun Sep 13 09:29:00 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to guest /usr/src; make nativekernel + installkernel; reboot into kernel #1; identical PoC produces rc=0 aq_len=2 with no panic and clean module unload (run.2.log), while baseline kernel #0 panicked (run.log/panic.txt).", "fix_evidence": "findings/poc/DF-3466/run.2.log (patched run), findings/poc/DF-3466/run.log + panic.txt (baseline), findings/poc/DF-3466/fix.diff (git apply --check clean against sys/)" } |