DragonFlyBSD Kernel Audit
DF-2886 / verdict.json
← back to finding ↓ download raw
{
  "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"
  ]
}