{
  "finding_id": "DF-3133",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "REPRODUCED (deterministic harness; dirfs is vkernel-only so no live-boot test \u2014 DF-0806/0807/3054 precedent). dirfs_node_chsize (dirfs_subr.c:778-793) runs nvtruncbuf/nvextendbuf on the vnode BEFORE the host truncate() is attempted, never checks dirfs_node_absolute_path() for NULL, and never rolls back on failure. Demonstrated: (A) unlinked-but-open file \u2014 absolute_path NULL (dn_parent cleared by nremove vnops:914-916) -> truncate(NULL) EFAULT after the B_DELWRI buffer holding a write(2)-acknowledged write was destroyed WITHOUT flush (vfs_vm.c:300-302) and the VM object truncated; host data still alive through the open fd; guest re-read resurrects the OLD data (acknowledged write silently reverted); mmap view desyncs. (B) absolute path >MAXPATHLEN \u2014 the deep tree is really constructed on the host via fd-relative openat() (the dirfs passive-fd-cache mechanism), proving constructibility by an unprivileged user; same EFAULT-after-damage; 4x240 boundary path truncates normally. (C) valid path, root-owned file: host truncate EPERM, guest buffers/pager destroyed anyway (no ownership check in the setattr size branch vnops:491-503; chsize also lacks the IMMUTABLE/APPEND guard chtimes has at :656-657); host file verified untouched afterwards. FIXED variant (NULL check + host-first): ENAMETOOLONG/errno with zero damage in every scenario. Impact ceiling: vkernel data integrity + availability (silent loss of acknowledged writes, stale-data resurrection, cached-view denial of arbitrary dirfs files); no host-kernel crash, no escalation.",
  "exploit_chain": "vkernel user -> (own file) open+ftruncate after unlink, or deep >1024-byte path built via fd-relative creation, or ftruncate of a host-root-owned file -> VOP_SETATTR size branch (no ownership check) -> dirfs_node_chsize -> nvtruncbuf destroys buffers/pager (dirty B_DELWRI data lost, VM object resized) -> host truncate() fails EFAULT/EPERM -> error returned but damage committed: acknowledged writes gone, reads resurrect old host data, mmap SIGBUSes; persists for the vnodes cache lifetime",
  "evidence": "harness.c (verbatim absolute_path :377-443 + chsize :748-799 control flow; nvtruncbuf/nvextendbuf stubbed to documented vfs_vm.c semantics; real truncate/pread errno outcomes); run.log \u2014 BUG A1..A4, BUG B1/B2 + fd-relative constructibility precondition, BUG C1/C2 + host file untouched; exit code 2, 9/9 confirmations, 3/3 runs identical MD5; fix.diff applies cleanly (git apply --check RC=0 local + guest /usr/src); fix_base_cc.log vs fix_patched_cc.log compile-neutral",
  "kernel_refs": [
    "sys/vfs/dirfs/dirfs_subr.c:778",
    "sys/vfs/dirfs/dirfs_subr.c:779",
    "sys/vfs/dirfs/dirfs_subr.c:786",
    "sys/vfs/dirfs/dirfs_subr.c:377",
    "sys/vfs/dirfs/dirfs_subr.c:433",
    "sys/vfs/dirfs/dirfs_vnops.c:491",
    "sys/vfs/dirfs/dirfs_vnops.c:914",
    "sys/kern/vfs_vm.c:146",
    "sys/kern/vfs_vm.c:165",
    "sys/kern/vfs_vm.c:280",
    "sys/kern/vfs_vm.c:300",
    "sys/kern/vfs_syscalls.c:4117"
  ],
  "poc_changes": "Harness written fresh (no seed). Iterations: (1) helper that joined path fragments ignored its format arg (scenario B silently tested the wrong directory) \u2014 replaced with a concatenating helper and re-verified scenario A unchanged; (2) added debug prints mid-debug, removed. All scenario results were re-captured after the fix; 3/3 identical runs.",
  "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",
  "runtime_sec": 20,
  "guest_dirty": 0,
  "build_cmd": "cd poc/DF-3133 && sh build.sh",
  "run_cmd": "cd poc/DF-3133 && sh run.sh",
  "code_hash": "337f2b453ae25a910ef9aca70e8194f85c4389b75d915f116fe9697097de4050",
  "notes": "chsize is the ONLY ch* wrapper without a NULL-path assert \u2014 its NULL path flows into truncate(NULL) AFTER the destructive helpers; distinct from DF-0855 (KKASSERT family), DF-0808 (nrename EFAULT, no page-cache damage), DF-3057 (write-path bread clobber), DF-3054/0855/0856 (findfd family + alloc_file leak). nvtruncbufs data-buffer destroy is by-design for a SUCCESSFUL truncate; the bug is applying it before the host outcome is known.",
  "recommended_fix": "dirfs_node_chsize: check absolute_path for NULL (ENAMETOOLONG), perform the host truncate() FIRST, and only run nvtruncbuf/nvextendbuf + dn_size update after it succeeds (fix.diff).",
  "fix_status": "not_testable",
  "fix_kernel_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",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 1,
  "fix_verdict": "fix.diff (NULL check -> ENAMETOOLONG; host truncate first; buffer/pager mutation only on success) applies cleanly (git apply --check RC=0 on the local sys/ tree and on the guest /usr/src). Compile-neutral: patched vs unpatched dirfs_subr.c in the vkernel64 ad-hoc env fail with IDENTICAL first errors (pre-existing errno.h include breakage, same as DF-3054/DF-0806 documented) \u2014 fix_base_cc.log vs fix_patched_cc.log. Behavior validated by the harness FIXED variants (zero damage, clean error propagation) in every scenario. Live boot validation not_testable: dirfs is vkernel-only and not compiled into the guest host kernel, so the patched path cannot be exercised by a host-kernel reboot.",
  "fix_evidence": "fix.diff; fix_base_cc.log vs fix_patched_cc.log (identical first error); harness FIXED variant output in run.log (FIXED A/B lines)"
}