DF-5838 / verdict.json
{ "finding_id": "DF-5838", "status": "untested", "verdict": "Contract defect confirmed statically: cluster_collectbufs() documents that only buffers whose block size matches blksize are collected (sys/kern/vfs_cluster.c:1719-1721), but the getcacheblk SZMATCH filter at sys/kern/vfs_cluster.c:1746-1748 uses last_bp->b_bcount instead, while len (1737), the collection stride (1745) and cluster_writes endbp/teardown (1312-1342) are all computed in blksize units. A caller passing bp->b_bcount != blksize would hand ffs_reallocblks a mixed-size children list; ffs walks the block maps one fs_bsize block per child (sys/vfs/ufs/ffs_alloc.c:470-497) and frees every childs old block as a full fs_bsize block (ffs_alloc.c:535-541), so fragment-backed children corrupt the cylinder-group allocation bitmap - and the DIAGNOSTIC guards that would panic (ffs_alloc.c:375-388) are compiled out of release kernels. Not executed on the guest: every current caller (UFS sys/vfs/ufs/ufs_readwrite.c:377-380 full-block gate; HAMMER1 sys/vfs/hammer/hammer_vnops.c:841; HAMMER2 sys/vfs/hammer2/hammer2_vnops.c:1177; tmpfs sys/vfs/tmpfs/tmpfs_vnops.c:864-881) passes b_bcount == blksize, and an unprivileged user cannot decouple the two values through any VOP path, so the defect is latent. One-line fix authored.", "reproduced": false, "impact": "none", "confidence": "likely", "exploit_chain": "", "evidence": "findings/poc/DF-5838/VERDICT.md (full path:line analysis); findings/poc/DF-5838/fix.diff (one-line contract alignment); decisive lines: sys/kern/vfs_cluster.c:1746-1748 (b_bcount used) vs :1719-1721 (contract) vs :1737/:1745 (blksize arithmetic); sys/vfs/ufs/ffs_alloc.c:470-497+535-541 (full-block assumption downstream); sys/kern/vfs_bio.c:2799-2802 (SZMATCH semantics)", "kernel_refs": [ "sys/kern/vfs_cluster.c:1746", "sys/kern/vfs_cluster.c:1719", "sys/kern/vfs_cluster.c:1737", "sys/vfs/ufs/ffs_alloc.c:470", "sys/vfs/ufs/ffs_alloc.c:535", "sys/kern/vfs_bio.c:2799" ], "poc_changes": "no PoC built - latent defect with no reachable trigger in this tree (all callers pass b_bcount == blksize); verification intentionally skipped per contract for Low hardening findings", "attempts": 0, "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": 0, "guest_dirty": 0, "build_cmd": "", "run_cmd": "", "code_hash": "", "notes": "Adjacent safe behavior noted: gap compaction keeps only buffers after the LAST gap (sys/kern/vfs_cluster.c:1750-1775) - conservative and correct for VOP_REALLOCBLKS contiguity, just an optimization-window shrink, not filed.", "recommended_fix": "Pass blksize (not last_bp->b_bcount) to getcacheblk in cluster_collectbufs so the SZMATCH filter matches the documented contract and the surrounding blksize-based cluster arithmetic.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff authored against the read-only sys/ tree (one line); not built on the guest because behavior is byte-identical for every existing caller (b_bcount == blksize in all reachable paths) - nothing observable to measure (fix_status not_testable).", "fix_evidence": "findings/poc/DF-5838/fix.diff" } |