DF-0916 / fix.diff
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) |