fs: cifs: Initialize filesystem timestamp ranges
authorDeepa Dinamani <deepa.kernel@gmail.com>
Fri, 22 Mar 2019 21:32:35 +0000 (14:32 -0700)
committerDeepa Dinamani <deepa.kernel@gmail.com>
Fri, 30 Aug 2019 14:27:18 +0000 (07:27 -0700)
Fill in the appropriate limits to avoid inconsistencies
in the vfs cached inode times when timestamps are
outside the permitted range.

Also fixed cnvrtDosUnixTm calculations to avoid int overflow
while computing maximum date.

References:

http://cifs.com/

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/d416ff7c-c536-406e-a951-4f04b2fd1d2b

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Acked-by: Jeff Layton <jlayton@kernel.org>
Cc: sfrench@samba.org
Cc: linux-cifs@vger.kernel.org
fs/cifs/cifsfs.c
fs/cifs/netmisc.c

index 3289b56..7a75726 100644 (file)
 #include "dfs_cache.h"
 #endif
 
+/*
+ * DOS dates from 1980/1/1 through 2107/12/31
+ * Protocol specifications indicate the range should be to 119, which
+ * limits maximum year to 2099. But this range has not been checked.
+ */
+#define SMB_DATE_MAX (127<<9 | 12<<5 | 31)
+#define SMB_DATE_MIN (0<<9 | 1<<5 | 1)
+#define SMB_TIME_MAX (23<<11 | 59<<5 | 29)
+
 int cifsFYI = 0;
 bool traceSMB;
 bool enable_oplocks = true;
@@ -142,6 +151,7 @@ cifs_read_super(struct super_block *sb)
        struct inode *inode;
        struct cifs_sb_info *cifs_sb;
        struct cifs_tcon *tcon;
+       struct timespec64 ts;
        int rc = 0;
 
        cifs_sb = CIFS_SB(sb);
@@ -161,6 +171,18 @@ cifs_read_super(struct super_block *sb)
        /* BB FIXME fix time_gran to be larger for LANMAN sessions */
        sb->s_time_gran = 100;
 
+       if (tcon->unix_ext) {
+               ts = cifs_NTtimeToUnix(0);
+               sb->s_time_min = ts.tv_sec;
+               ts = cifs_NTtimeToUnix(cpu_to_le64(S64_MAX));
+               sb->s_time_max = ts.tv_sec;
+       } else {
+               ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MIN), 0, 0);
+               sb->s_time_min = ts.tv_sec;
+               ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MAX), cpu_to_le16(SMB_TIME_MAX), 0);
+               sb->s_time_max = ts.tv_sec;
+       }
+
        sb->s_magic = CIFS_MAGIC_NUMBER;
        sb->s_op = &cifs_super_ops;
        sb->s_xattr = cifs_xattr_handlers;
index ed92958..49c17ee 100644 (file)
@@ -949,8 +949,8 @@ static const int total_days_of_prev_months[] = {
 struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
 {
        struct timespec64 ts;
-       time64_t sec;
-       int min, days, month, year;
+       time64_t sec, days;
+       int min, day, month, year;
        u16 date = le16_to_cpu(le_date);
        u16 time = le16_to_cpu(le_time);
        SMB_TIME *st = (SMB_TIME *)&time;
@@ -966,15 +966,15 @@ struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
        sec += 60 * 60 * st->Hours;
        if (st->Hours > 24)
                cifs_dbg(VFS, "illegal hours %d\n", st->Hours);
-       days = sd->Day;
+       day = sd->Day;
        month = sd->Month;
-       if (days < 1 || days > 31 || month < 1 || month > 12) {
-               cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days);
-               days = clamp(days, 1, 31);
+       if (day < 1 || day > 31 || month < 1 || month > 12) {
+               cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, day);
+               day = clamp(day, 1, 31);
                month = clamp(month, 1, 12);
        }
        month -= 1;
-       days += total_days_of_prev_months[month];
+       days = day + total_days_of_prev_months[month];
        days += 3652; /* account for difference in days between 1980 and 1970 */
        year = sd->Year;
        days += year * 365;