⬢ DragonFlyBSD Kernel Audit
DF-5330 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/pc64/isa/clock.c
+++ b/sys/platform/pc64/isa/clock.c
@@ -1166,6 +1166,22 @@
 
 	tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
 
+	/*
+	 * DF-5330: a wall clock set before the epoch (or pushed before
+	 * it by the timezone / adjkerntz adjustment) wraps the unsigned
+	 * long tm to a huge value.  The year loop below would then spin
+	 * for ~5e16 iterations with preemption/interrupts deferred
+	 * (crit_enter at the top of resettodr) and masterclock_lock held,
+	 * hanging the kernel permanently.  Sanity-bound the conversion to
+	 * year 9999 and leave the RTC untouched if the time is out of
+	 * range.
+	 */
+	if (tm > (unsigned long)86400 * 366 * (9999 - 1970 + 1)) {
+		writertc(RTC_STATUSB, rtc_statusb);
+		crit_exit();
+		return;
+	}
+
 	writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60;	/* Write back Seconds */
 	writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60;	/* Write back Minutes */
 	writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24;	/* Write back Hours   */