DF-0842 / panic.txt
DF-0842 -- panic signature (unpatched 6.5-DEVELOPMENT #0 kernel)
================================================================
Trigger: kldload df0842_harness.ko (calls the real in-kernel z_inflate*
symbols on a 20-byte truncated-but-valid zlib stream that decodes ~1.8KB of
output before the input is exhausted mid-decode).
Captured from dfbsd-qemu/boot.log lines 217-239:
DF-0842: harness start -- about to call z_inflateInit_ (state->window will be NULL, wsize=0)
DF-0842: inflateInit_ ret=0 (expect 0=Z_OK); now calling z_inflate(Z_FINISH) on a 20-byte truncated stream
Fatal user address access from kernel mode from kldload at ffffffff80bcac8a
Fatal trap 12: page fault while in kernel mode
cpuid = 2; lapic id = 2
fault virtual address = 0x0
fault code = supervisor write data, page not present
instruction pointer = 0x8:0xffffffff80bcac8a
stack pointer = 0x10:0xfffff801183936f0
frame pointer = 0x10:0xfffff80118393768
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 0, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 980
current thread = pri 6
kernel: type 12 trap, code=2
CPU2 stopping CPUs: 0x0000003b
stopped
Stopped at memcpy+0xfa: repe movsq (%rsi),%es:(%rdi)
db>
Interpretation:
* fault VA = 0x0 -> write through state->window == NULL
* supervisor WRITE data -> it is a WRITE (zmemcpy into the window), confirming
the missing-allocation sink, not a read.
* Stopped at memcpy+0xfa -> zmemcpy() == kernel bcopy/memcpy, the call inside
updatewindow() at hammer2_zlib_inflate.c:382/389/392.
Path: z_inflate() -> inf_leave (mode<CHECK, output produced) -> updatewindow()
-> zmemcpy(state->window=NULL, ...) -> page fault at 0x0 -> panic.
This is a NULL-pointer-WRITE DoS at a fixed address (page 0 is unmapped in the
kernel), so no privilege-escalation chain is derivable -- pure local DoS.
================================================================================
REAL UNPRIVILEGED TRIGGER (same kernel, same RIP 0xffffffff80bcac8a)
================================================================================
Trigger: maxx (uid 1001) runs `cat /h2mnt/zd/big.bin` on a crafted HAMMER2
image. The image's ZLIB data block decompresses to 200 KB >> avail_out (16384);
inflate fills the output buffer and exits via inf_leave in MATCH/LIT (< CHECK)
with output produced -> updatewindow() zmemcpy through NULL window -> panic.
Captured from dfbsd-qemu/boot.log lines 255-272 (immediately after the read):
Fatal trap 12: page fault while in kernel mode
cpuid = 0; lapic id = 0
fault virtual address = 0x0
fault code = supervisor write data, page not present
instruction pointer = 0x8:0xffffffff80bcac8a
stack pointer = 0x10:0xfffff80117b0c8d8
frame pointer = 0x10:0xfffff80117b0c950
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 0, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = Idle
current thread = pri 12
kernel: type 12 trap, code=2
CPU0 stopping CPUs: 0x0000003e
stopped
Stopped at memcpy+0xfa: repe movsq (%rsi),%es:(%rdi)
db>
The RIP (0xffffffff80bcac8a) and the faulting instruction (memcpy+0xfa /
`repe movsq (%rsi),%es:(%rdi)`) are byte-identical to the harness panic,
confirming both reach the same sink: updatewindow() zmemcpy(state->window=NULL).
Reachability chain (all in GENERIC, HAMMER2 is the root filesystem):
read(2) as unprivileged user
-> hammer2_vop_strategy / hammer2_strategy_read (hammer2_strategy.c)
-> hammer2_strategy_read_completion (hammer2_strategy.c:458-484)
-> hammer2_decompress_ZLIB_callback (hammer2_strategy.c:229, inflate@257)
-> z_inflate(Z_FINISH) (hammer2_zlib_inflate.c:556)
-> inf_leave guard TRUE (hammer2_zlib_inflate.c:1018-1019)
-> updatewindow() (hammer2_zlib_inflate.c:366, no alloc)
-> zmemcpy(state->window=NULL,...) (hammer2_zlib_inflate.c:382/389/392)
-> write to VA 0x0 -> fatal trap 12.