DragonFlyBSD Kernel Audit
DF-2999 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2999",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "REPRODUCED unprivileged permanent kernel livelock on a HAMMER1 mount, then fix validated. hammer_vop_setattr (sys/vfs/hammer/hammer_vnops.c:2261-2286) passes the unclamped 64-bit va_size to nvtruncbuf()/nvextendbuf(); ftruncate(0x7ffffffffffff000)+pwrite+ftruncate(0x7fffffffffff8000) by an unprivileged user puts the thread into an unkillable R4 kernel loop (nvtruncbuf truncloffset wraps to INT64_MIN at sys/kern/vfs_vm.c:149; nvnode_pager_setsize unmap loop at vfs_vm.c:486-495 iterates ~2^63 times holding vp->v_token and the vm_object lock). kill -9 ineffective; concurrent rm parks in D state; directory listing corrupted by the 2^63-scale size; guest recoverable only by killing QEMU. Identical signature to DF-2921 (the HAMMER2 trigger of the same vfs_vm.c bug) - this is the HAMMER1 call-site. Patched kernel (va_size clamped to OFF_MAX - HAMMER_XBUFSIZE in setattr + write path, fix.diff) returns EFBIG instantly; smoke test clean.",
  "exploit_chain": "unpriv user -> ftruncate(fd,0x7ffffffffffff000) [extend via nvextendbuf] -> pwrite 1 byte near EOF -> ftruncate(fd,0x7fffffffffff8000) [truncate via nvtruncbuf: 0x7fffffffffff8000+(65536-0x8000) wraps to 2^63] -> nvnode_pager_setsize unmap loop ~2^63 iterations -> unkillable kernel livelock, poisoned vnode, guest unshut-downable",
  "evidence": "run.log: baseline output - extend OK, pwrite OK, second ftruncate never returns; ps shows PID 1047 R4; kill -9 ineffective; rm in D5; 'total 18014398509543426' directory corruption | build.log: fix validation on kernel #2 - 'extend-> File too large', 0.00s, EXIT=1; smoke test OK | fix.diff: va_size clamp in hammer_vop_setattr + end-offset clamp in hammer_vop_write",
  "kernel_refs": [
    "sys/vfs/hammer/hammer_vnops.c:2261",
    "sys/vfs/hammer/hammer_vnops.c:2269",
    "sys/vfs/hammer/hammer_vnops.c:2276",
    "sys/vfs/hammer/hammer_vnops.c:664",
    "sys/kern/vfs_vm.c:149",
    "sys/kern/vfs_vm.c:464",
    "sys/kern/vfs_vm.c:486"
  ],
  "poc_changes": "adapted DF-2921's op2921.c trigger (same offsets) to a HAMMER1 vn-backed mount; path taken from argv; added cleanup path (unreachable on vulnerable kernel)",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 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); fix validated on #2: Sat Sep  5 01:44:36 UTC 2026",
  "runtime_sec": 45,
  "guest_dirty": 0,
  "build_cmd": "cc -O -o /tmp/op2999 /tmp/op2999.c -Wall ; (fix) cd /usr/src && make -j4 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC",
  "run_cmd": "/tmp/op2999 /mnt/h1/maxx2999.bin   (as unprivileged user; HAMMER1 mounted at /mnt/h1)",
  "code_hash": "abb865fe2e2305c834677ac776e3dc67997f155ba1c3659f6472622d45302b5e",
  "notes": "baseline wedged guest twice (second time inadvertently on the probe-only kernel, re-confirming). Guest restored to clean snapshot afterwards. Related: DF-2921 (hammer2 trigger of the same vfs_vm.c arithmetic; its fix.diff fixes the shared root cause - either fix suffices; this pack's fix.diff is the HAMMER1-local clamp).",
  "recommended_fix": "Clamp va_size (and write end-offset) to OFF_MAX - HAMMER_XBUFSIZE in hammer_vnops.c; reject negative va_size (see fix.diff); alternatively apply DF-2921's vfs_vm.c clamp globally.",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly 6.5-DEVELOPMENT #2: Sat Sep  5 01:44:36 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Baseline kernel #0: unpriv ftruncate wedge (unkillable R4, D-state rm, unshut-downable guest). Patched kernel #2 (fix.diff): same PoC returns EFBIG in 0.00s; no wedge; HAMMER1 smoke test (create/write/truncate/read/unlink) clean.",
  "fix_evidence": "build.log (fix validation section); VERDICT.md (Fix validation section)"
}