DragonFlyBSD Kernel Audit
DF-2993 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2993",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "A single NFSv3 READDIR (or READDIRPLUS) with count=0 from any export-allowed client drives nfsrv_readdir into an infinite kernel loop (the eof short-cut requires uio_resid>0 and vop_write_dirent returns success-with-zero-cookies on resid 0), permanently pinning an nfsd thread holding slp->ns_token; reproduced twice on the stock INVARIANTS guest \u2014 after the trigger the console writer starves, ssh flaps and dies, and in run 1 the whole guest became unresponsive with no panic signature (hard livelock).",
  "exploit_chain": "mountd/portmap probes to obtain the 32-byte dir fh -> one ~120-byte UDP READDIR(count=0) per nfsd thread -> all server threads spin forever in kernel mode -> NFS socket service dead + host userland starvation.",
  "evidence": [
    "run.log \u2014 two runs: control READDIR(count=8192) 'reply OK', trigger READDIR(count=0) no reply; ssh rc=124/255 progression; vm.sh status down (run 1)",
    "serial console in run 2: 'NULL: reply 24 bytes in 0.0001s' then '--- TRIGGER readdir count=0 ---' then total silence",
    "VERDICT.md \u2014 full line-accurate root-cause chain (nfs_serv.c:2977-2984, 3066-3095, 3120-3124; vfs_subr.c:2566-2568; ufs_vnops.c:1612-1636)",
    "run.fixed.log \u2014 patched kernel returns an immediate error reply for count=0 and stays responsive"
  ],
  "kernel_refs": [
    "sys/vfs/nfs/nfs_serv.c:2977",
    "sys/vfs/nfs/nfs_serv.c:3066",
    "sys/vfs/nfs/nfs_serv.c:3120",
    "sys/vfs/nfs/nfs_serv.c:3277",
    "sys/vfs/nfs/nfs_serv.c:3407",
    "sys/kern/vfs_subr.c:2566",
    "sys/vfs/ufs/ufs_vnops.c:1612"
  ],
  "poc_changes": "wrote nfspoc.c from scratch (raw SUNRPC/UDP client: rpcbind GETPORT, mountd MNT, NFS v3 NULL/READDIR/LOOKUP/WRITE); no seed existed",
  "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": 150,
  "guest_dirty": 0,
  "build_cmd": "cc -O -o /root/nfspoc /root/nfspoc.c",
  "run_cmd": "NFSPOC_SRCPORT=821 NFSPOC_TIMEOUT=5 /root/nfspoc readdir <fh-hex> 0 1",
  "code_hash": "7faf5661fb7604b4672cb2d79210c692f0f3611e6a0159d6083684f27cee7f2c",
  "notes": "Guest left clean (vm.sh reset with-src after verification). nfs_privport=1 on this guest: client bound a reserved source port, matching a remote attacker who is root on their own host. The nfsd spin holds slp->ns_token, so one request also kills all further service on that socket.",
  "recommended_fix": "Reject count/dircount == 0 (siz <= 0) with NFSERR_TOOSMALL in nfsrv_readdir and nfsrv_readdirplus before the retry loop (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 returns an immediate NFSERR_TOOSMALL reply for READDIR count=0 and stays fully responsive; normal READDIR unchanged. Bad behavior gone.",
  "fix_evidence": [
    "run.fixed.log"
  ]
}