⬢ DragonFlyBSD Kernel Audit
DF-4563 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4563",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "vn(4) runs the whole VNF_DESTROY disk teardown from inside the rawdev close path (vnclose -> disk_destroy -> sync disk/devfs messages -> release_dev x3) while a concurrent last-but-one close of the same unit drops its own cdev sysrefs: the destroy worker double-puts the sysref and the kernel panics with the SRF_PUTAWAY assertion (release_dev -> devfs_destroy_dev_worker -> devfs_destroy_related_worker). Reproduced 2/2 from fresh vm.sh reset with-src boots with a minimal two-thread racing-close program; the same interleave first wedges the losing close and all new devfs operations in uninterruptible sleep for minutes. The losing diskclose also dereferences dp->d_slice/dp->d_rawdev after the softc kfree (post-free window, exploitable in principle via same-class slab recycling; sizeof(vn_softc)=2816). Trigger requires SYSCAP_RESTRICTEDROOT (vn ioctls), so this is a privileged-user kernel crash/DoS, not an unpriv escalation. fix.diff (deferred teardown via callout) validated: stock kernel panics on the identical trigger, patched kernel completes 800/800 iterations with zero stalls and no panic.",
  "exploit_chain": "root (SYSCAP_RESTRICTEDROOT): open /dev/vn (clone unit >=4), VNIOCATTACH swap-backed, VNIOCDETACH (arms VNF_DESTROY), open the unit node again, race close() of the two descriptors -> winners vnclose teardown races losers cdev sysref releases -> sysref double-put -> kernel panic (demonstrated); pre-panic the guests devfs wedges system-wide in uninterruptible sleep for minutes (demonstrated); post-free dp->d_slice deref gives a memory-corruption window if the freed 2816-byte slab block is recycled with controlled content (code-derived, not demonstrated to corruption).",
  "evidence": "panic.txt and panic.2.txt (identical sysref_put SRF_PUTAWAY panics, backtrace through devfs_destroy_dev_worker); run.patched.log (patched kernel: DONE n=800 worst_close=0.000s stalls>1s=0, EXIT=0); VERDICT.md narrative; stall.c minimal trigger; env.txt guest details",
  "kernel_refs": [
    "sys/dev/disk/vn/vn.c:455-477",
    "sys/dev/disk/vn/vn.c:169-189",
    "sys/kern/subr_disk.c:1126-1161",
    "sys/kern/subr_disk.c:527-555",
    "sys/vfs/devfs/devfs_core.c:1440-1460"
  ],
  "poc_changes": "PoC authored fresh in this run (no seed): stall.c (2-thread racing close of a detached cloned vn unit). Harness bugs fixed during bring-up: barrier handshake rewritten with generation counters, unit discovery switched from broken minor() decode to stat-rdev scan, cross-pair unit interference eliminated by stat-only scanning, fork/exec p_args spray capped properly.",
  "attempts": 5,
  "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": 2900,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -pthread -o stall stall.c",
  "run_cmd": "./stall 800",
  "code_hash": "f5da425c51c77487b1b67f4384465558ff5168f0702d6d9ee8039f58547cfa66",
  "notes": "Two fresh-boot baseline reproductions (panic) + fix validation build (make nativekernel, installkernel, reboot) with identical trigger completing cleanly. patch-note.txt discloses an additional scale observation on the patched kernel (~750 distinct clone units churned rapidly -> process-local D-state waitmsg wedge) that the stock kernel cannot reach because it panics first; flagged as needing a reference-counted struct disk lifetime for a complete family fix. Guest reset to clean-source snapshot after the run.",
  "recommended_fix": "Defer the VNF_DESTROY teardown out of the rawdev close path (callout, fix.diff); full fix is a reference-counted struct disk lifetime in the disk layer so vnclose/diskclose cannot free the softc while any disk-layer close is still in flight.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Identical trigger (./stall 800): stock kernel panics (sysref_put SRF_PUTAWAY) on both fresh-boot baseline runs; patched kernel (fix.diff, nativekernel build #1 Mon Sep 21 15:46:08 UTC 2026) completed 800/800 iterations, worst close latency 0.000s, zero >1s stalls, no panic. Demonstrated vulnerability eliminated by the fix.",
  "fix_evidence": "run.patched.log (patched DONE n=800, EXIT=0); panic.txt / panic.2.txt (baseline panics); build performed on guest: cd /usr/src && make nativekernel KERNCONF=X86_64_GENERIC, kernel installed and booted before the patched run."
}