⬢ DragonFlyBSD Kernel Audit
DF-2717 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2717",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Locking protocol violation confirmed line-accurate by inspection: nlookup_init (sys/kern/vfs_nlookup.c:149-166), nlookup_init_at (:225-228,242) and the nlookup retry (:1376-1378) read the shared fd_ncdir/fd_nrdir nchandle pairs with no fd_spin, while kern_chdir/kern_fchdir write them under fd_spin and kern_chroot (vfs_syscalls.c:2059-2066) writes fd_nrdir under p_token only; cache_copy (vfs_cache.c:996-1026) is two adjacent non-atomic loads with a delayed _cache_hold. Both claimed race primitives were storm-tested live and did NOT land in a quantified budget: 156,107,562 cross-mount fchdir swaps vs 161,845,152 reader nlookups in 150 s (torn pair) and 399,820 last-ref-drop dance cycles vs 122,075,241 reader copies in 120 s (hold-after-drop) both ran clean, so no escalation, no leak, no refcount corruption was observed for DF-2717 itself. However the prescribed full storm panicked the guest 3/3 times within 90 s (nlookup+0x66c = vfs_nlookup.c:767, NULL+0x84); crash-dump analysis proves this is a DISTINCT adjacent bug: rmdir of the process cwd defers a namecache zap which completes under churn while fd_ncdir still holds the last ref, leaving a topology-disconnected node (nc_parent=NULL) that the unlocked fd_ncdir reads deliver into the .. walk, whose unguarded nctmp.ncp = nctmp.ncp->nc_parent at :756 feeds a NULL nch.ncp dereferenced at :767. The panic does not depend on the missing lock (a locked reader copies the same disconnected handle) and should be filed separately as an unprivileged reliable local DoS. fix.diff carries both the fd_spin protocol fix (Part A) and the NULL-parent guard (Part B); the patched kernel survived the same storm budget that panicked 3/3 and shows no measurable open() throughput regression.",
  "exploit_chain": "",
  "evidence": "Dedicated sub-storms: run-S1-swap-only.log (150 s clean, 1.56e8 swaps), run-S2-dance-only.log (120 s clean, 1.22e8 opens); adjacent panic: panic-smoke-console.txt + panic-2-console.txt + run-S3-full-panic.log (3/3 nlookup+0x66c) and kgdb-frame6-locals.log (nch.ncp=0x0, nl_nch.ncp nc_parent=0 nc_refs=30, path ../../../tmp/df2717/a); fix validation: run-fixed-storm.log (patched kernel clean), bench-stock.log vs bench-fixed.log",
  "kernel_refs": [
    "sys/kern/vfs_nlookup.c:149",
    "sys/kern/vfs_nlookup.c:159",
    "sys/kern/vfs_nlookup.c:225",
    "sys/kern/vfs_nlookup.c:242",
    "sys/kern/vfs_nlookup.c:756",
    "sys/kern/vfs_nlookup.c:767",
    "sys/kern/vfs_nlookup.c:1376",
    "sys/kern/vfs_cache.c:1006",
    "sys/kern/vfs_cache.c:1023",
    "sys/kern/vfs_cache.c:763",
    "sys/kern/vfs_cache.c:766",
    "sys/kern/vfs_syscalls.c:1906",
    "sys/kern/vfs_syscalls.c:2059",
    "sys/kern/kern_descrip.c:2411"
  ],
  "poc_changes": "Replaced the seed sketch with a mode-selectable pthread storm (df2717_storm.c argv[3] bitmask): bit0 fchdir cross-mount swapper (tmpfs vs hammer2 dirs for distinct mount pointers), bit1 relative ..-walking chdir swapper, bit2 volatile dance (mkdir vNNN / chdir vNNN / rmdir vNNN / chdir parent) that manufactures last-ref drops of fd_ncdir-held namecache nodes, bit3 relative-path open readers; added stats output and a bench_open.c microbenchmark for the fix A/B.",
  "attempts": 8,
  "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": 5400,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -pthread -o df2717_storm df2717_storm.c && cc -O2 -o bench_open bench_open.c",
  "run_cmd": "./df2717_storm 90 3 0xf   (attribution sub-storms: 0x9 swap-only 150 s, 0xc dance-only 120 s, 0xe no-fchdir 60 s)",
  "code_hash": "ac281e4081c87e260e2e2dc891b7b20f2210e19316fd3cdbc3c78453ad3cfbb0",
  "notes": "Adjacent bug discovered and root-caused with crash dump: unguarded NULL nc_parent in the .. walk (vfs_nlookup.c:756 -> :767) fed by a deferedzap disconnect of the rmdir-d process cwd; panics 3/3 under the full storm as an unprivileged user within 90 s - recommend filing as a separate finding (reliable unpriv local DoS; fix.diff Part B addresses it). DF-2717 itself: window quantified narrow (1.6e8 torn-pair and 1.2e8 hold-after-drop opportunities with zero hits); theoretical UAF remains closed as not demonstrated on this guest. debug.nlookup_debug sysctl bits are kprintf verbosity only and cannot force the retry path. Jail variant skipped: fd_njdir has no concurrent writer post-jail, so its torn-read surface is nil; the .. gate was exercised via tmpfs/hammer2 crossings in every run.",
  "recommended_fix": "Take fd_spin around the fd_ncdir/fd_nrdir/fd_njdir cache_copy reads in nlookup_init/nlookup_init_at/nlookup retry, make kern_chroot use fd_spin like kern_chdir, and NULL-guard nctmp.ncp->nc_parent in the .. walk (fall back to nl_rootnch) so a topology-disconnected cwd cannot panic line 767."
}