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 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.