DF-5452 / nxirq.c
/* * DF-5452 PoC — nexus_alloc_resource() indexes irq_rman[cpuid] with a * debug-only (INVARIANTS-gated) assertion; on production kernels the plain * documented API feeds it cpuid = -1. * * subr_bus.c:3293-3300 bus_alloc_resource() -> BUS_ALLOC_RESOURCE(...,-1) * nexus.c:376-379 case SYS_RES_IRQ: * KASSERT(cpuid >= 0 && cpuid < ncpus) <- NO-OP * rm = &irq_rman[cpuid]; <- [-1] * systm.h:94-112 KASSERT/KKASSERT are empty without INVARIANTS * * This guest kernel is X86_64_GENERIC with INVARIANTS disabled, so the * negative index reaches rman_reserve_resource() on the static memory that * precedes irq_rman[] — an out-of-bounds struct-rman interpretation whose * outcome (silent NULL vs wild list corruption) depends on unrelated statics. * * Demonstrated contrast on the same free vector: * bus_alloc_legacy_irq_resource() (valid cpuid) -> succeeds * bus_alloc_resource() (default -1) -> silently operates on * &irq_rman[-1] and fails */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/rman.h> #include <sys/systm.h> static int nxirq_probe(device_t); static int nxirq_attach(device_t); static void nxirq_identify(driver_t *, device_t); static device_method_t nxirq_methods[] = { DEVMETHOD(device_identify, nxirq_identify), DEVMETHOD(device_probe, nxirq_probe), DEVMETHOD(device_attach, nxirq_attach), DEVMETHOD_END }; static driver_t nxirq_driver = { "nxirq", nxirq_methods, 0 }; static devclass_t nxirq_devclass; DRIVER_MODULE(nxirq, nexus, nxirq_driver, nxirq_devclass, NULL, NULL); #define POC_VEC 5 /* legacy IRQ 5 (free on this box) */ static void nxirq_identify(driver_t *drv, device_t parent) { if (device_find_child(parent, "nxirq", 0) == NULL) BUS_ADD_CHILD(parent, parent, 0, "nxirq", 0); } static int nxirq_probe(device_t dev) { device_set_desc(dev, "nexus irq cpuid PoC"); return (0); } static int nxirq_attach(device_t dev) { struct resource *r; int rid; /* leg 1: the helper that supplies a valid cpuid (subr_bus.c:3302) */ rid = 0; r = bus_alloc_legacy_irq_resource(dev, &rid, POC_VEC, RF_SHAREABLE); kprintf("DF-5452: legacy helper (valid cpuid): res=%p rid=%d\n", r, rid); if (r != NULL) bus_release_resource(dev, SYS_RES_IRQ, rid, r); /* leg 2: plain bus_alloc_resource -> cpuid defaults to -1 */ rid = 1; r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, POC_VEC, POC_VEC, 1, RF_SHAREABLE); kprintf("DF-5452: plain API (cpuid -1 default): res=%p\n", r); if (r != NULL) bus_release_resource(dev, SYS_RES_IRQ, rid, r); kprintf("DF-5452: sizeof(struct rman)=%zu; nexus indexed " "irq_rman[-1] == base-%zu bytes with the KASSERT compiled out\n", sizeof(struct rman), sizeof(struct rman)); return (0); } |