DF-3222 / verdict.json
{ "finding_id": "DF-3222", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "dirfs_mounts copyinstr fallback re-interprets a failed user data pointer as a kernel address and copystr()s from it (dirfs_vfsops.c:129); the vkernel copystr has no fault handling, so a mount(2) with data=(void*)0x1008 crashes the vkernel in kernel mode. Verified on the guest: Fatal trap 12 in copystr+0x5 (movzbl (%rdi),%eax), current process vkmount2. Requires mount privilege (vkernel root / dirfs fscap / vfs.usermount=1), hence Low. fix.diff (remove the fallback) validated: mount fails cleanly with EFAULT (Bad address) and the vkernel survives.", "exploit_chain": "mount-privileged user in vkernel calls mount(\"dirfs\", dir, 0, (void*)0x1000) -> domount passes uap->data -> copyinstr(0x1000) EFAULT -> copystr(0x1000,...) as kernel pointer -> first byte load faults -> Fatal trap 12, whole-vkernel panic. Mapped-address variant: bounded read of up to 1023 bytes of vkernel-kernel memory into dm_path (indirectly observable only); no out-of-bounds write.", "evidence": [ "run.log: Fatal trap 12 ... current process = 2 (vkmount2), Stopped at 0x726b85: movzbl (%rdi),%eax", "VERDICT.md: 0x726b85 symbolized as copystr+0x5 (vkernel copyio.c:255 loop head)", "run.fixed.log: mount failed: Bad address + STILL-ALIVE \u2014 vkernel alive with fix.diff" ], "kernel_refs": [ "sys/vfs/dirfs/dirfs_vfsops.c:126", "sys/vfs/dirfs/dirfs_vfsops.c:129", "sys/platform/vkernel64/platform/copyio.c:251", "sys/kern/vfs_conf.c:457", "sys/kern/vfs_syscalls.c:416" ], "poc_changes": "vkmount2.c written fresh (mount(2) with data=(void*)0x1000); harness identical to DF-3218s (custom vkernel build after bit-rot include fixes, FFS root image, vkinit wrapper, fifo console).", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026 (guest); vkernel VKDIRFS ident", "runtime_sec": 900, "guest_dirty": 1, "build_cmd": "same vkernel build as DF-3218 (nativekernel KERNCONF=VKDIRFS)", "run_cmd": "inside vkernel booted by run.sh: /bin/vkmount2 /hostroot", "code_hash": "9e999e027e8805737a6b2f3f4f9520350983662de262af2dec87b8707667a7df", "notes": "No in-tree caller passes a kernel data pointer (vfs root mount passes NULL), so the fallback serves nobody and its only reachable effect for real callers is the crash. vfs.usermount=0 verified on guest; non-root reachability requires the dirfs fscap or usermount=1.", "recommended_fix": "Delete the copystr fallback; fail the mount on copyinstr error (see fix.diff). If a kernel-internal mount API ever needs dirfs, it should pass the path through a UIO_SYSSPACE-aware interface, not by guessing pointer provenance.", "fix_status": "fixed", "fix_kernel_uname": "vkernel VKDIRFS (DragonFly 6.5-DEVELOPMENT, guest scratch tree with fix.diff)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Fallback removed, vkernel relinked, identical PoC re-run: copyinstr EFAULT returns as mount failed: Bad address; vkernel alive and shell responsive (run.fixed.log).", "fix_evidence": [ "run.fixed.log", "fix-build.log", "build.fixed-kernel.log", "fix.diff" ] } |