DF-2666 / verdict.json
{ "finding_id": "DF-2666", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "The missing fdrop(fp) on hammer2_ioctl_recluster()'s two error returns (VFS_ROOT failure; the focus==NULL EINVAL branch) is certain by code inspection against the one-way ref-transfer contract of hammer2_cluster_reconnect/kdmsg_iocom_reconnect, but the leak branch could not be entered on the stock guest: 200/200 RECLUSTER calls took the success path (healthy iroot cluster), kern.openfiles delta was exactly 0 (ref accounting balanced), and no userland-constructible degraded-cluster state was found that yields focus==NULL with nchains!=1. Ceiling is one permanently pinned struct file per failing call, privileged caller only (SYSCAP_NOVFS_IOCTL). Bonus: ~1250 rapid reconnect cycles stress-tested the reconnect kill/join/teardown ordering with no wedge or panic.", "exploit_chain": "", "evidence": [ "run.log: RECLUSTER_OK=200 RECLUSTER_EINVAL=0, OPENFILES DELTA=0 across 200 calls (success-path balance, leak branch unenterable)", "VERDICT.md section 1: static proof of the two leak paths (hammer2_ioctl.c:214/226-231) against the ownership contract (kern_dmsg.c:130 'We own that ref now')", "fix.diff: adds fdrop(fp) when error != 0 after holdfp", "dmesg diff (610 new lines): per-cycle VOLDATA DUMP/INITIATE SPANs/CONN WAS TERMINATED proving teardown re-entry into hammer2_autodmsg with msglk released — no panic over ~1250 cycles" ], "kernel_refs": [ "sys/vfs/hammer2/hammer2_ioctl.c:212", "sys/vfs/hammer2/hammer2_ioctl.c:214", "sys/vfs/hammer2/hammer2_ioctl.c:226-231", "sys/vfs/hammer2/hammer2_iocom.c:77-85", "sys/kern/kern_dmsg.c:128-131", "sys/kern/kern_dmsg.c:149-152" ], "poc_changes": "fresh PoC (no seed); sized down from 2000 to 200 iterations after measuring ~1 s per reconnect cycle (hz/2 teardown sleeps)", "attempts": 2, "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": 210, "guest_dirty": 0, "build_cmd": "cc -O -I/usr/src/sys -o df2666_trigger df2666_trigger.c", "run_cmd": "sh /root/poc/df2666/run_df2666.sh (guest, root; mounts /dev/vn0@testvol on /mnt/h2poc2666, 200x HAMMER2IOC_RECLUSTER)", "code_hash": "28d3a0ed65f2c5a5cdc3f166a5f924d6fde32a4b9eda77ad19ce582a7525aa73", "notes": "Privilege-gated (root) resource leak; also noted lockless reads of cluster->focus/array[0].chain in the same function (speculative transient-NULL race, not observed in 200 runs). Fix validation not run: branch unenterable, patch changes no executable path of this run -> fix_status not_testable.", "recommended_fix": "In hammer2_ioctl_recluster(), fdrop(fp) whenever the function returns an error after a successful holdfp() (the reference is transferred into iocom->msg_fp only on the success branches)." } |