DF-5351 / msiabi_row128.c
/* * DF-5351 crasher: msi_alloc(count=128) on the last online CPU. * * With count=128 the scan loop in ioapic_abi_msi_alloc_intern() reaches * i=128 and then j walks 0..127, i.e. intr = 128..255: * - ioapic_irqmaps[cpuid][192..255] are read (ioapic_abi.c:1276) and * written (ioapic_abi.c:1287-1293): one full row past the end of the * 192-entry row (the next CPU's map row). * - intrs[64..127] = 192..255 is written into the caller's array * (ioapic_abi.c:1295) -- past any 32-entry contract array. * - msi_setup(intr, cpuid) is called for intr=192..255 * (ioapic_abi.c:1296): msi_intr[192..255] is an OOB read past the * 192-entry msi_intr[] table, and setidt(0x20+192 .. 0x20+255) * overwrites the IPI IDT gates (vectors 224..255) and writes past * the 256-entry per-CPU IDT (vectors 256..287). * Expect: panic on the next IPI (6-CPU guest fires IPIs constantly). * If the machine somehow survives, the printed zone[64..127] values >= 192 * still prove the row-crossing map writes. */ #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_IOAPIC; static int zone[256]; static void row128(int cpuid) { int i, rc; for (i = 0; i < 256; ++i) zone[i] = 0x7B7B7B7B; kprintf("msiabi_row128: msi_alloc(count=128, cpu%d) ...\n", cpuid); rc = MachIntrABI_IOAPIC.msi_alloc(zone, 128, cpuid); kprintf("msiabi_row128: rc=%d\n", rc); if (rc == 0) { kprintf("msiabi_row128: zone[0..3] ="); for (i = 0; i < 4; ++i) kprintf(" %d", zone[i]); kprintf("\nmsiabi_row128: zone[120..127] ="); for (i = 120; i < 128; ++i) kprintf(" %d", zone[i]); kprintf(" (values >= 192 prove writes into " "ioapic_irqmaps[cpuid][192..255])\n"); /* not reached if IPI delivery kills us first */ MachIntrABI_IOAPIC.msi_release(zone, 128, cpuid); kprintf("msiabi_row128: released\n"); } } static int msiabi_modevent(module_t mod __unused, int type, void *data __unused) { switch (type) { case MOD_LOAD: kprintf("msiabi_row128: loaded\n"); row128(ncpus - 1); kprintf("msiabi_row128: SURVIVED (unexpected)\n"); return 0; case MOD_UNLOAD: return 0; default: return EOPNOTSUPP; } } static moduledata_t msiabi_row128_mod = { "msiabi_row128", msiabi_modevent, NULL }; DECLARE_MODULE(msiabi_row128, msiabi_row128_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); |