DragonFlyBSD Kernel Audit
DF-2946 / fix.diff
← back to finding ↓ download raw
--- 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)