⬢ DragonFlyBSD Kernel Audit
DF-3382 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-3382",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "panic",
 "confidence": "certain",
 "verdict": "BIOCSETBLEN guards only bd_bif!=NULL while bpf_setif() allocates buffers only when bd_sbuf==NULL; after ifconfig destroy detaches the descriptor (bd_bif=NULL, buffers retained), BIOCSBLEN raises bd_bufsize to 512KiB over the still-4096-byte kmalloc buffers and the next BIOCSETIF skips bpf_allocbufs, so catchpacket() appends ~512KiB of packets into the 4096-byte store buffer. Reproduced on the stock guest: 512 controlled 1.4KiB A packets written ~727KiB past the allocation; kernel survived the flood then died with Fatal trap 9: general protection fault in cache_nlookup_maybe_shared+0x100 dereferencing a corrupted namecache object. This is a corrupt-AND-continue primitive (kernel ran seconds after the overflow) with fully controlled content - the strongest of the four findings; a uid0 chain (spray kmalloc(4096) victims around the store buffer) is plausible on this no-SMAP/SMEP/KASLR guest but the destroy-interface step requires root, so no privilege boundary beyond the bpf-fd holder is crossed; documented as ceiling. Fix validated on rebuilt kernel: BIOCSBLEN now returns EINVAL once buffers exist, guest survives.",
 "exploit_chain": "ifconfig tun0 create -> open /dev/bpf1 + BIOCSETIF(tun0) [alloc 2x4096] -> ifconfig tun0 destroy [bd_bif=NULL, buffers kept] -> BIOCSBLEN(512K) [accepted] -> BIOCSETIF(lo0) [alloc skipped] -> 512 loopback packets -> catchpacket writes ~727KiB of controlled data past kmalloc(4096) -> namecache corruption -> GPF panic. uid0 chain (slab groom + victim overwrite) not completed: triggers destroy step is root-only; time budget spent on mandatory fix validation.",
 "evidence": [
  "panic.txt: Fatal trap 9 GPF at cache_nlookup_maybe_shared+0x100",
  "run.log: full stdout incl. BIOCSBLEN -> 524288 (buffers still 4096!) and 512 packets sent",
  "VERDICT.md: primitive characterization and corrupt-and-continue analysis"
 ],
 "kernel_refs": [
  "sys/net/bpf.c:794-806",
  "sys/net/bpf.c:1128-1134",
  "sys/net/bpf.c:320-326",
  "sys/net/bpf.c:1580-1583",
  "sys/net/bpf.c:1418-1463"
 ],
 "poc_changes": "Written fresh: uses tun0 (if_tun is compiled into X86_64_GENERIC) as the destroyable bpf-attached interface; floods lo0 with 1400-byte UDP packets after rebinding; disc(4) rejected because it is not clone-destroyable.",
 "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": 20,
 "guest_dirty": 1,
 "build_cmd": "cc -O -o trigger trigger.c",
 "run_cmd": "ifconfig tun0 create && ./trigger",
 "code_hash": "54d56d297bc870c406c96fec0afdf8fe6cff752363eb3c432ec5240aeb0255cf",
 "notes": "The GPF landed in namecache (slab neighbor of the store buffer), proving cross-subsystem corruption rather than an immediate copy fault. Guest crashed seconds AFTER the program exited.",
 "recommended_fix": "Reject BIOCSETBLEN when bd_sbuf != NULL (validated in fix.diff).",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Fri Sep 11 22:24:51 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (fix.diff applied; make nativekernel + installkernel in guest)",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "Baseline: Fatal trap 9 GPF in cache_nlookup_maybe_shared after ~727KiB overflow. Patched: identical sequence fails cleanly at BIOCSBLEN: EINVAL (bd_sbuf != NULL guard); guest survives.",
 "fix_evidence": [
  "run.patched.log"
 ]
}