]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
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 3289b566463f91cc913d886f7db3c41189746d90..7a75726442ad2e0fe7710a234650409db8f99d79 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 ed92958e842d3502b4d54817796c0f4a81d54c38..49c17ee182544d6f986334379d76976b6f3ef3b3 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;