DF-4228 / model_div0.c
/* * DF-4228 harness: divide-by-zero in cyapa_poll_thread() * (sys/dev/smbus/cyapa/cyapa.c:1200) * * static int cyapa_idle_freq = 1; <- sysctl debug.cyapa_idle_freq RW * static int cyapa_slow_freq = 20; <- sysctl debug.cyapa_slow_freq RW * static int cyapa_norm_freq = 100; <- sysctl debug.cyapa_norm_freq RW * (cyapa.c:227-235, root-writable, unbounded) * * tsleep(&sc->poll_flags, 0, "cyapw", * (hz + freq - 1) / freq); <-- cyapa.c:1200 * * freq is re-assigned from one of the three sysctls every poll iteration * (cyapa.c:1202-1210). Setting any of them to 0 makes the kernel thread * execute an integer division by zero -> #DE -> kernel panic. * * This userspace model executes the identical arithmetic in the identical * integer types to show the fault (userspace: SIGFPE; kernel: panic). */ #include <stdio.h> #include <stdlib.h> #include <signal.h> static int freq; static void sigfpe_handler(int sig) { (void)sig; printf("RESULT: SIGFPE - integer division by zero raised " "(in kernel context: #DE trap -> panic)\n"); exit(0); } int main(void) { int hz = 100; /* kern.hz */ int timeout; signal(SIGFPE, sigfpe_handler); freq = 0; /* sysctl debug.cyapa_idle_freq=0 */ printf("cyapa_poll_thread: freq=%d, computing (hz + freq - 1) / freq\n", freq); fflush(stdout); timeout = (hz + freq - 1) / freq; /* cyapa.c:1200 */ /* not reached when freq == 0 */ printf("tsleep timeout = %d\n", timeout); printf("RESULT: no fault (unexpected)\n"); return 1; } |