DF-3087 / verdict.json
{ "finding_id": "DF-3087", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Deterministic kernel NULL-deref panic, reproduced on the stock INVARIANTS kernel from a fresh vm.sh reset on the first clean attempt. An AUTH_KERB/FULLNAME request makes nfssvc_nfsd() return ENEEDAUTH with the request parked in nfsd->nfsd_nd and NFSD_REQINPROG set (nfs_syscalls.c:609-623); the documented daemon resume via nfssvc(NFSSVC_AUTHIN|NFSSVC_NFSD) re-enters nfssvc_nfsd() whose local nd is NULL (:448) and is never reloaded from nfsd->nfsd_nd (:549-570), so the reply do-loop dereferences nd->nd_procnum at :671 with writes_todo==0. Fatal trap 12, fault VA 0x70 (offsetof nd_procnum), 'Stopped at sys_nfssvc+0x3d4: movl 0x70(%rdi),%eax', current process = kerbd. Root-only trigger (nfssvc requires SYSCAP_RESTRICTEDROOT); base-system nfsd(8) cannot trigger it because its zeroed nsd_authstr makes the :616-620 copyouts fail first (request becomes RC_DROPIT), so severity is Low: local privileged-user kernel panic, plus a theoretical remote amplifier against any non-base daemon implementing the kerb AUTHIN protocol. fix.diff (reload nd from nfsd->nfsd_nd on resume; clear nfsd->nfsd_nd where nd is freed) validated by full kernel rebuild: baseline panics, patched kernel completes the resume and keeps serving (run.fixed.log), guest survives.", "exploit_chain": "root runs kerbd (or any daemon implementing the 4.4BSD kerb ENEEDAUTH/AUTHIN nfsd protocol) -> remote NFS client (or local sender) submits one AUTH_KERB/RPCAKN_FULLNAME NFSv3 request -> kernel parks it and returns ENEEDAUTH -> daemon calls nfssvc(NFSSVC_AUTHIN|NFSSVC_NFSD, nsd) -> NULL-deref at nfs_syscalls.c:671 -> Fatal trap 12, all CPUs stopped, guest down. No privilege escalation: read-fault on NULL+offset (0x70), panic-only.", "evidence": [ "findings/poc/DF-3087/panic.txt -- 'Fatal trap 12 ... fault virtual address = 0x70 ... Stopped at sys_nfssvc+0x3d4: movl 0x70(%rdi),%eax', current process = kerbd (stock kernel #0, fresh reset)", "findings/poc/DF-3087/run.log -- stock-kernel run: ENEEDAUTH (errno 81) returned to userland, AUTHIN resume, guest down", "findings/poc/DF-3087/run.fixed.log -- kernel #1 with fix.diff: same ENEEDAUTH flow, resume completes, RC=124 (timeout, nfsd keeps serving), guest up", "findings/poc/DF-3087/kerbd.c -- self-contained trigger (daemon + kerb request sender)", "findings/poc/DF-3087/fix.diff -- one-line reload + nfsd_nd NULL-clearing, git-apply-able" ], "kernel_refs": [ "sys/vfs/nfs/nfs_syscalls.c:448", "sys/vfs/nfs/nfs_syscalls.c:549-570", "sys/vfs/nfs/nfs_syscalls.c:609-623", "sys/vfs/nfs/nfs_syscalls.c:664-682", "sys/vfs/nfs/nfs_syscalls.c:671", "sys/vfs/nfs/nfs_socket.c:2392-2434", "sys/vfs/nfs/nfs_socket.c:2897", "sbin/nfsd/nfsd.c:826-841" ], "poc_changes": "Authored from scratch: minimal ADDSOCK+NFSD daemon with pre-allocated auth/verf buffers (the copyouts at :616-620 must succeed for ENEEDAUTH to escape), a sender child crafting the 19-word AUTH_KERB FULLNAME request, and the fatal AUTHIN resume. Two setup iterations were needed: the guest auto-starts stock nfsd(8) whose workers steal every nfsrv_wakenfsd assignment (PoC must killall nfsd), and a leftover zapd worker did the same.", "attempts": 3, "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 (baseline); #1 Sun Sep 6 04:53:45 UTC 2026 (fix)", "runtime_sec": 95, "guest_dirty": 0, "build_cmd": "cc -O -o /root/kerbd /root/kerbd.c (in-guest, base cc; needs <vfs/nfs/*.h> from /usr/src)", "run_cmd": "killall nfsd; sleep 1; /root/kerbd 20497", "code_hash": "4639e7019efbb517af8826dd402adad4be6058657e497f7d42ffff81858326d2", "notes": "errno 81 = ENEEDAUTH on DragonFly. The same missing-reload also makes nfsd->nfsd_nd leak when the daemon abandons the request (never freed anywhere) and leaves a stale pointer after :760's kfree -- fix.diff clears it. Base-system impact ceiling: none (nfsd(8) RC_DROPITs); impact requires a kerb-protocol daemon, hence Low.", "recommended_fix": "In nfssvc_nfsd()'s NFSD_REQINPROG else-branch, reload nd = nfsd->nfsd_nd; clear nfsd->nfsd_nd wherever nd is kfree'd (see fix.diff).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Sun Sep 6 04:53:45 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "vm.sh reset with-src (stock #0) -> kerbd panics the guest (run.log, panic.txt). Same tree + fix.diff (patch -p1) -> make nativekernel+installkernel -> reboot -> identical PoC: ENEEDAUTH returned, AUTHIN resume re-dispatches the parked request and the nfsd keeps serving until the 40s timeout; guest up (run.fixed.log). Bad behavior gone.", "fix_evidence": "findings/poc/DF-3087/run.fixed.log; findings/poc/DF-3087/fix.diff" } |