DragonFlyBSD Kernel Audit
DF-0821 / run.log
← back to finding ↓ download raw
=== 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.