DF-2946 / fix.diff
--- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -197,11 +197,19 @@ init_param1(void) hz = HZ_DEFAULT; TUNABLE_INT_FETCH("kern.hz", &hz); + /* + * hz feeds unsigned divides (ustick/nstick/ntp_default_tick_delta) + * and systimer period math all over the kernel. Reject garbage: + * 0 panics at the divides below (DF-0173), >1000000 zeroes ustick + * (userspace-reachable divide-by-zero), negative values poison the + * MSSYNC period computation. + */ + if (hz < 1 || hz > 1000000) + hz = HZ_DEFAULT; stathz = hz + 1; TUNABLE_INT_FETCH("kern.stathz", &stathz); + /* stathz=0 divides by zero in _systimer_init_periodic (DF-2946) */ + if (stathz < 1) + stathz = hz + 1; profhz = stathz; ustick = 1000000 / hz; nstick = 1000000000 / hz; --- a/sys/kern/kern_systimer.c +++ b/sys/kern/kern_systimer.c @@ -265,6 +265,11 @@ _systimer_init_periodic(systimer_t info, systimer_func_t func, void *data, bzero(info, sizeof(struct systimer)); + /* defense in depth: never divide by a non-positive frequency */ + if (freq <= 0) + freq = 1; + if ((flags & SYSTF_100KHZSYNC) && freq <= 100000) info->periodic = sys_cputimer->fromhz(100000) * (100000 / freq); if ((flags & SYSTF_MSSYNC) && freq <= 1000) |