DF-0869 / panic.txt
--- DF-0869 panic signature (unpatched #0 kernel, INVARIANTS on) ---
--- Trigger: HAMMERIOC_ADD_VOLUME boot_area_size=-1 vol_size=2^49 ---
--- Captured from dfbsd-qemu/boot.log before guest reset ---
HAMMER(df0869) Initialize freemap volume 1
dscheck(vn2): bio_offset 262143 is not on a sector boundary (ssize 512)
panic: assertion "error == 0" failed in hammer_ioc_volume_add at /usr/src/sys/vfs/hammer/hammer_volume.c:118
cpuid = 1
Trace beginning at frame 0xfffff801166dac48
hammer_ioc_volume_add() at hammer_ioc_volume_add+0x5c6 0xffffffff80930806
hammer_ioc_volume_add() at hammer_ioc_volume_add+0x5c6 0xffffffff80930806
hammer_ioctl() at hammer_ioctl+0xf0a 0xffffffff8093ed1a
hammer_vop_ioctl() at hammer_vop_ioctl+0x48 0xffffffff80958978
vop_ioctl() at vop_ioctl+0x63 0xffffffff8070a793
vn_ioctl() at vn_ioctl+0xb1 0xffffffff807080e1
Debugger("panic")
CPU1 stopping CPUs: 0x0000003d
stopped
Stopped at Debugger+0x7c: movb $0,0xbdaf09(%rip)
db>
--- Mechanism ---
boot_area_size = -1 in the ioc propagates into hammer_format_volume_header:
vol_alloc = root.vol_bot_beg; // 0x40000 = 256 KiB
vol_alloc += ioc->boot_area_size; // -1
ondisk->vol_buf_beg = vol_alloc; // 0x3FFFF = 262143 (NOT sector-aligned)
vol_buf_end = ioc->vol_size & ~HAMMER_BUFMASK = 2^49 (passes the only
check `HAMMER_VOL_BUF_SIZE < 0` because vol_buf_size is a huge positive).
hammer_format_freemap then issues hammer_bread() against the freshly
installed volume at offsets derived from vol_buf_beg. The first such
I/O is at bio_offset 262143 -- not a 512-byte boundary -- and dscheck()
rejects it, hammer_bread returns EINVAL, and KKASSERT(error == 0) at
hammer_volume.c:118 panics the kernel.
The root cause is missing bounds + sanity validation in
hammer_format_volume_header: boot_area_size, memory_log_size and
vol_size are attacker-controlled int64s summed into vol_alloc with
only a single signed-<0 check on the final vol_buf_size.