DF-2790 / verdict.json
{ "finding_id": "DF-2790", "status": "reproduced", "reproduced": 1, "impact": "corruption", "confidence": "certain", "verdict": "All three claim layers confirmed on the stock guest via the harness (blist(64), count==0): (1) all-free leaf: blist_alloc(bl,0) returns 0 successfully and CLEARS the whole 64-bit leaf (mask = ~0>>64 is UB; on x86-64 the mod-64 shift leaves mask=~0); the subsequent alloc(1) returns SWAPBLK_NONE - 64 blocks of capacity silently lost while bl_free still counts them. (2) partially-free leaf: alloc(0) walks j to 64 where the shifted-out mask becomes 0, matches anything, wipes the whole leaf and returns blk+64 - an OUT-OF-RANGE block number; subsequent alloc(1) then hands out block 0 again (double-alloc of freed-but-not-allocated state on the swap blist). (3) blist_create: no BLIST_MAXBLKS guard - while (radix < blocks) with blocks > 2^61 wraps the int64 radix to 0 and loops forever (NOT executed on the guest; arithmetic is exact and the KKASSERT(skip>0) cannot fire before the wrap). On the fix kernel alloc(0) returns SWAPBLK_NONE and alloc(1) succeeds on both leaf states; create gains a domain KKASSERT. In-tree callers pass count in [1,64] and clamped sizes, so latent hardening.", "exploit_chain": "count==0 -> UB shift -> mask ~0 (or 0 at j=64) -> whole leaf cleared / out-of-range grant blk+64 -> swap-slot double-assignment on the swap blist", "evidence": "harness.log T1: alloc(0)=0 then alloc(1)=NONE (capacity leak); T2: alloc(0)=64 (out-of-range grant) + leaf wipe; fix kernel T1/T2: alloc(0)=NONE, alloc(1)=0", "kernel_refs": [ "sys/kern/subr_blist.c:419", "sys/kern/subr_blist.c:188", "sys/kern/subr_blist.c:241" ], "poc_changes": "blist_create takes one argument; SWAPBLK_NONE is -2^63 not -1", "attempts": 2, "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", "runtime_sec": 60, "guest_dirty": 0, "build_cmd": "cd /root/h41 && make", "run_cmd": "kldload ./h41.ko; sysctl -w debug.h41.cmd=1 2", "code_hash": "85d6e241caa2a7fb1fb44b80c7736a4e83c36d29314b0c96ce91769bc9bdf839", "notes": "count>64 design panic and >2^61 create wrap documented, not executed (wedge risk)", "recommended_fix": "Guard count domain at blist_alloc/allocat/free/fill and KKASSERT blocks in [1, BLIST_MAXBLKS] in blist_create", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Mon Oct 26 01:57:23 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (h41 fix kernel, all 41 hardening fixes applied)", "fix_verdict": "A/B: baseline T1/T2 show leaf wipe + capacity leak + out-of-range grant; fix kernel returns SWAPBLK_NONE for count<1 at all four entry points and the create-domain KKASSERT compiles." } |