DragonFlyBSD Kernel Audit
DF-0916 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/smbfs/smbfs_subr.c b/sys/vfs/smbfs/smbfs_subr.c
--- a/sys/vfs/smbfs/smbfs_subr.c
+++ b/sys/vfs/smbfs/smbfs_subr.c
@@ -156,6 +156,18 @@
 	 */
 	smb_time_local2server(tsp, tzoff, &t);
 	t &= ~1;
+	/*
+	 * Clamp the seconds value to the range representable in a DOS
+	 * date (year <= 2107, the maximum encodable in the 7-bit DOS year
+	 * field).  Without this, an attacker-controlled tv_sec of INT64_MAX
+	 * (or -1 reinterpreted as u_long on 64-bit) makes `days` astronomical
+	 * and the for(year=1970;;year++) loop below run for ~3e11 / ~6e14
+	 * iterations -- a kernel livelock DoS (CWE-834, unbounded loop).
+	 * Reachable via utimensat() on an SMBFS vnode: VOP_SETATTR ->
+	 * smbfs_setattr -> smbfs_smb_setpattr/setftime -> here.
+	 */
+	if (t > 4323456000UL)	/* seconds from 1970-01-01 to 2106-12-31 */
+		t = 4323456000UL;
 	if (lasttime != t) {
 		lasttime = t;
 		lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)