⬢ DragonFlyBSD Kernel Audit
DF-3466 / verdict.json
← back to finding ↓ download raw
{
 "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/)"
}