DF-2886 / verdict.json
{ "finding_id": "DF-2886", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "uiomovez()'s UIO_USERSPACE branch copyouts cnt = min(iov_len, n) bytes from ZeroPage, but ZeroPage is exactly PAGE_SIZE (kern_slaballoc.c:316); any n > 4096 reads past the allocation into the user's buffer. KLD harness proved the primitive: 64 stable non-zero kernel-heap bytes (slab bookkeeping) delivered to an unprivileged nobody process in 4/4 runs on stock kernel #0; the one-line PAGE_SIZE clamp (fix.diff, kernel #1) eliminated all leaked bytes while preserving the zero-fill contract. Latent engine defect: the sole in-tree caller (NFSv3 short-read zero-fill, nfs_vnops.c:1433) is only ever reached with UIO_SYSSPACE uios (nfs_bio.c:1080-1117, nfs_vnops.c:433-448) which take the safe bzero() branch, so no stock syscall path triggers it today - filed Low for that reason, certain about the primitive itself.", "exploit_chain": "", "evidence": [ "run.log: 4 runs as nobody, each 'RESULT: LEAK CONFIRMED', 64/64/64/63 non-zero bytes at offsets >=4096, bytes[0..4095] zero", "leak_sample_run1/2/3.txt: identical sparse slab-metadata qwords at fixed offsets (cross-run stability = kernel memory, not noise)", "run.fixed.log: 2 runs on PAGE_SIZE-clamped kernel #1 - 0 non-zero bytes, read still returns 65536 zeros", "build.log: module builds -Werror clean via SYSDIR=/usr/src/sys conf/kmod.mk", "VERDICT.md: reachability trace showing both nfs_readrpc_uio callers pass UIO_SYSSPACE (bzero branch)" ], "kernel_refs": [ "sys/kern/kern_subr.c:241", "sys/kern/kern_subr.c:246", "sys/kern/kern_slaballoc.c:316", "sys/vfs/nfs/nfs_vnops.c:1433", "sys/vfs/nfs/nfs_bio.c:1080", "sys/vfs/nfs/nfs_vnops.c:448", "sys/vfs/nfs/nfs_vfsops.c:106" ], "poc_changes": "authored fresh (no seed); bring-up fixes: KLD Makefile needs SYSDIR=/usr/src/sys for out-of-tree builds; devfs needs explicit .d_open or open(2) returns ENODEV", "attempts": 4, "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: Wed Sep 2 22:00:57 UTC 2026 (fix validation)", "runtime_sec": 1500, "guest_dirty": 1, "build_cmd": "cd /tmp/uioz && make && cc -O -o uioz_trigger uioz_trigger.c (Makefile: SYSDIR=/usr/src/sys; KMOD=uioz; SRCS=uiozleak.c; .include \"${SYSDIR}/conf/kmod.mk\")", "run_cmd": "kldload /tmp/uioz/uioz.ko && su -m nobody -c /tmp/uioz/uioz_trigger", "code_hash": "88fc1b3bdf068e308733b8a09857fdafecd054f13d798c12691583f9918a0168 (uiozleak.c); 8ddb24c9ed7c63859177e26e8a2ae6a8ca716d3e7a9c810b726e621c20078eef (uioz_trigger.c)", "notes": "Leak window is the 60KB following a boot-time kmem_slab_alloc; observed content = slab allocator metadata (no kernel pointers in 4 runs). Reachability caveat documented in VERDICT.md; severity Low because no stock syscall path passes UIO_USERSPACE with n>4096 to uiomovez today. Guest reset to with-src snapshot after validation.", "recommended_fix": "Clamp cnt to PAGE_SIZE per loop iteration in uiomovez (see fix.diff).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Wed Sep 2 22:00:57 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Applied fix.diff to /usr/src/sys/kern/kern_subr.c in-guest, make -j4 nativekernel + make installkernel + reboot into kernel #1; re-ran the identical PoC twice as nobody: 0 non-zero bytes past offset 4096 (vs 64 on baseline), read() still zero-fills the full 65536 bytes; guest stable, no panic.", "fix_evidence": [ "run.fixed.log: 2 runs, 'RESULT: no leak observed', 'non-zero bytes >= 4096 : 0 / 61440'", "run.log: baseline comparison, 4 runs LEAK CONFIRMED", "fix.diff: git-apply-clean one-hunk clamp" ] } |