DragonFlyBSD Kernel Audit
DF-2994 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2994",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "With an export configured '-public -index=<missing file>', a v3 LOOKUP using the public filehandle (fhlen=0) for any directory lacking the index file makes nfsrv_lookup vput() a vnode it unlocked at line 565 and never re-locked \u2014 vput -> vn_unlock -> lockmgr(LK_RELEASE) on an unheld lock panics unconditionally. Reproduced on the stock INVARIANTS guest with the exact predicted backtrace (panic: lockmgr: LK_RELEASE: no lock held / vput / nfsrv_lookup); guest dropped to DDB, ssh dead.",
  "exploit_chain": "single pre-auth-style UDP LOOKUP(public fh, '/') -> deterministic kernel panic (remote DoS) whenever WebNFS is exported with an index file",
  "evidence": [
    "panic.txt \u2014 full serial-console panic text with the vput()/nfsrv_lookup() backtrace and db> prompt",
    "run.log \u2014 NULL baseline healthy, trigger line, ssh never returns, vm.sh status down",
    "VERDICT.md \u2014 line-accurate chain: nfs_serv.c:565 vn_unlock, 568-590 index-lookup failure skips the re-lock/cache_vget block, 599/643 vput on unlocked vp; vfs_lock.c:703-707; kern_lock.c:767-768"
  ],
  "kernel_refs": [
    "sys/vfs/nfs/nfs_serv.c:565",
    "sys/vfs/nfs/nfs_serv.c:574",
    "sys/vfs/nfs/nfs_serv.c:599",
    "sys/vfs/nfs/nfs_serv.c:643",
    "sys/kern/vfs_lock.c:703",
    "sys/kern/kern_lock.c:767",
    "sys/vfs/nfs/nfs_subs.c:1183",
    "sys/kern/vfs_subr.c:2266"
  ],
  "poc_changes": "wrote nfspoc.c from scratch (lookup0 subcommand: v3 LOOKUP with fhlen=0 public filehandle)",
  "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": 0,
  "build_cmd": "cc -O -o /root/nfspoc /root/nfspoc.c",
  "run_cmd": "NFSPOC_SRCPORT=831 NFSPOC_TIMEOUT=5 /root/nfspoc lookup0 /",
  "code_hash": "7faf5661fb7604b4672cb2d79210c692f0f3611e6a0159d6083684f27cee7f2c",
  "notes": "Preconditions: NFS export with -public and index=<file> (WebNFS index); index file absent from the looked-up directory. vfs.nfs.nfs_privport=1 required a reserved source port. Panic is unconditional in this lockmgr (not INVARIANTS-only).",
  "recommended_fix": "Re-lock the original vp (vn_lock(vp, LK_EXCLUSIVE|LK_RETRY)) when the public-index nlookup fails, before continuing (fix.diff).",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Fri Sep  4 21:02:10 UTC 2026\troot@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Patched kernel answers the identical public-fh LOOKUP with a normal reply; no panic, guest stays up. Bad behavior gone.",
  "fix_evidence": [
    "run.fixed.log",
    "panic.txt"
  ]
}