⬢ DragonFlyBSD Kernel Audit
DF-5321 / run.log
← back to finding ↓ download raw
DF-5321 baseline (UNPATCHED production sys/bus/firewire/firewire.c)
====================================================================
guest: DragonFly dfbsd 6.5-DEVELOPMENT #0 X86_64_GENERIC, 6 vCPUs, no
FireWire hardware; module df5321.ko compiles the unmodified production
firewire.c in and drives its real completion paths
(fw_rcv / fw_tl2xfer / firewire_xfer_timeout / fw_get_tlabel /
fw_xfer_free_buf / fw_tl_free) from three lwkt threads modelling the
receiving interrupt context, the 10 Hz watchdog callout, and the
/dev/fw FW_ASYREQ ioctl waiter (fwdev.c: tsleep(xfer) -> wakeup ->
fw_xfer_free_buf).

--- mode 1: FW_ASYREQ scenario (run_mode1.sh) -------------------------
$ kldload /root/df5321/df5321.ko
$ sysctl kern.df5321_mode=1 kern.df5321_iters=3000
$ sysctl kern.df5321_fire=1
(ssh dies; serial console, full copy in run_mode1_console.log / panic.txt)

DF5321: mode 1 starting (3000 attempts, PRODUCTION firewire.c completion paths)
root0: split transaction timeout dst=0x101 tl=0x1 state=3

Fatal trap 12: page fault while in kernel mode
cpuid = 2; lapic id = 2
fault virtual address	= 0x8
fault code		= supervisor read data, page not present
instruction pointer	= 0x8:0xffffffff82601a8c
stack pointer	        = 0x10:0xfffff801183dfa40
frame pointer	        = 0x10:0xfffff801183dfa90
code segment		= base = 0x0, limit = 0xfffff, type = 0x1b
processor eflags	= interrupt enabled, resume, IOPL = 0
current process		= Idle
current thread           = pri 12 (CRIT)
kernel: type 12 trap, code=0

CPU2 stopping CPUs: 0x0000003b
 stopped
Stopped at      firewire_xfer_timeout+0xbc:     movq    0x8(%rax),%rax
db>

=> PANIC on the first attempt.  The watchdog CPU (crit section does not
   exclude other CPUs) dereferenced a tlabel whose xfer field read as
   NULL because the FW_ASYREQ waiter's fw_xfer_free_buf() -> fw_tl_free()
   had already unlinked and kfree'd that exact `struct tlabel` between
   the watchdog's STAILQ_FIRST() (firewire.c:336) and tl->xfer
   (firewire.c:337).  Use-after-free read of the freed 16-byte tlabel;
   with non-zeroed reuse it dereferences an attacker-influenced pointer.

--- mode 2: kernel-handler scenario (run.sh, act.hand = production
    fw_asy_callback_free, as fw_phy_config firewire.c:1078 and fw_bmr's
    fwmem_write_quad firewire.c:2169-2170 use) ---------------------------
$ kldload /root/df5321/df5321.ko
$ sysctl kern.df5321_mode=2 kern.df5321_iters=3000
$ sysctl kern.df5321_fire=1
(serial console; identical signature)

DF5321: mode 2 starting (3000 attempts, PRODUCTION firewire.c completion paths)
root0: split transaction timeout dst=0x101 tl=0x1 state=3

Fatal trap 12: page fault while in kernel mode
cpuid = 2; lapic id = 2
fault virtual address	= 0x8
fault code		= supervisor read data, page not present
instruction pointer	= 0x8:0xffffffff82601a8c
...
Stopped at      firewire_xfer_timeout+0xbc:     movq    0x8(%rax),%rax
db>

=> PANIC again on the first attempt.  Here the first completion
   (fw_xfer_done via either path) ran the production
   fw_asy_callback_free, whose fw_xfer_free() -> fw_tl_free() removed
   and kfree'd the tlabel under the scanning watchdog -> same tlabel
   use-after-free; absent the reuse-as-zeroed luck this is the
   double-free / wild-pointer deref primitive.

--- Both runs reproduced from a fresh `vm.sh reset with-src` boot;
    guest `down` at the db> prompt afterwards.