DragonFlyBSD Kernel Audit
DF-0869 / panic.txt
← back to finding ↓ download raw
--- 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.