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