DF-2614 / verdict.json
{ "finding_id": "DF-2614", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED on the stock INVARIANTS kernel and FIX VALIDATED on a rebuilt kernel. (1) Heap-pointer leak: mounting a hammer2 volume with cluster_fd = our socketpair end (hammer2_vfsops.c:1350-1357) and issuing HAMMER2IOC_REMOTE_ADD (hammer2_ioctl.c:308) as root prints 'volconf update 0xfffff801177797c0' (hammer2_iocom.c:376, %p of the kmalloc'd conn_state kdmsg_state_t set at kern_dmsg.c:189-190) to the console/msgbuf twice (ioctl + unmount-teardown via hammer2_autodmsg); a second unprivileged local user reads the pointer with plain 'dmesg | grep \"volconf update\"' (live-captured; msgbuf world-readable, lines also in /var/log/messages). Related ungated prints confirmed live: VOLDATA DUMP/INITIATE SPANs (:220/:236) fire at ordinary root-fs boot and unmount teardown, and vfsops prints 'hammer2_mount: hmp=%p pmp=%p' per mount (adjacent same-class sites, for the record). (2) Peer-driven console/msgbuf flood: 1000 one-way LNK_PAD frames from the cluster-socket peer produce exactly 1000 ungated 'RCVMSG %08x' kprintf lines (hammer2_iocom.c:135 via kern_dmsg.c:1220 default branch; rx validates only magic+size, no CRC, kern_dmsg.c:343-352) โ one console-lock+serial line per peer message, no flag, no rate limit. After fix.diff (drop the %p print, drop RCVMSG print, gate the four remaining prints behind hammer2_debug & 0x0100): identical trigger yields DELTA_volconf=0, DELTA_rcvmsg=0, REMOTE_ADD_OK, 1000 frames accepted per protocol, UNMOUNT_OK โ no functional regression. Low severity confirmed: local trigger paths are root-gated; exposure is (unprivileged) msgbuf/log read of a heap pointer and a cluster-peer-driven console/log flood; KASLR-defeat value applies to KASLR-enabled kernels (audit guest has none).", "exploit_chain": "root mounts hammer2 w/ cluster_fd (or any cluster CONN/remote-add history) -> kprintf volconf update %p (heap kdmsg_state_t) -> msgbuf + /var/log/messages -> unprivileged 'dmesg' read yields live kernel heap address (KASLR defeat material); cluster peer streams one-way unknown/LNK_PAD frames -> one RCVMSG kprintf per frame -> console-lock monopolization + msgbuf ring eviction", "evidence": [ "findings/poc/DF-2614/run.log โ FULL untrimmed stock-kernel run: 'volconf update 0xfffff801177797c0' x2, AFTER_rcvmsg=1000, TRANSMIT=2, sample RCVMSG lines", "findings/poc/DF-2614/unpriv_read.log โ live capture: user maxx reads the pointer via dmesg (count=2 + values) and /var/log/messages (count=2)", "findings/poc/DF-2614/run.fix.log โ same trigger on fix kernel: DELTA_volconf=0, DELTA_rcvmsg=0, REMOTE_ADD_OK, UNMOUNT_OK", "findings/poc/DF-2614/fix.diff โ pointer print removed, message-path prints gated behind hammer2_debug & 0x0100" ], "kernel_refs": [ "sys/vfs/hammer2/hammer2_iocom.c:135", "sys/vfs/hammer2/hammer2_iocom.c:220", "sys/vfs/hammer2/hammer2_iocom.c:236", "sys/vfs/hammer2/hammer2_iocom.c:241", "sys/vfs/hammer2/hammer2_iocom.c:376", "sys/vfs/hammer2/hammer2_iocom.c:378", "sys/vfs/hammer2/hammer2_vfsops.c:1350", "sys/vfs/hammer2/hammer2_ioctl.c:308", "sys/kern/kern_dmsg.c:189", "sys/kern/kern_dmsg.c:343", "sys/kern/kern_dmsg.c:1220" ], "poc_changes": "no seed existed; trigger written fresh (had to add errno.h include on first compile). Cluster connectivity obtained without the userland service daemon by passing a socketpair end as info.cluster_fd directly to mount(2), making the PoC process the cluster peer for the PAD-frame flood; REMOTE_ADD issued via ioctl on a file of the mounted volume.", "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": 2400, "guest_dirty": 0, "build_cmd": "cc -O -I/usr/src/sys -o df2614_trigger df2614_trigger.c (in guest, /root/poc/df2614/)", "run_cmd": "dfbsd-qemu/vm.sh run_root 'sh /root/poc/df2614/run_df2614.sh' (image prep + build + run + dmesg deltas)", "code_hash": "b053a74e1ef1990953cacb08bc0b8bccae5644983bf3943d88f8ce7ec9b13804", "notes": "Fix validated on rebuilt X86_64_GENERIC (nativekernel) kernels #3 and #5. Write-side absorbs 1000 frames in ~4ms (socket buffer); kernel emits one console+msgbuf line per frame โ the flood cost is per-message console/serial output, unbounded by any flag. Extra same-class ungated pointer prints observed live and left for the record (not part of this finding's lines): 'hammer2_mount: hmp=%p pmp=%p' (hammer2_vfsops.c) fires on every device mount.", "recommended_fix": "remove the %p kprintf at hammer2_iocom.c:376 and the per-message RCVMSG print at :135; gate the remaining message-path debug prints behind (hammer2_debug & 0x0100) as fix.diff does", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #5: Sat Aug 29 11:12:52 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "baseline (stock #0): 2 volconf pointer lines + 1000 RCVMSG lines; patched (#3 and #5, fix.diff applied, nativekernel rebuild + reboot): 0 and 0 with REMOTE_ADD_OK/UNMOUNT_OK and all 1000 peer frames still accepted โ leak and flood eliminated, no functional regression", "fix_evidence": "findings/poc/DF-2614/run.fix.log; findings/poc/DF-2614/run.log (baseline contrast)" } |