Commit cb7a69e6 authored by Deepa Dinamani's avatar Deepa Dinamani

fs: cifs: Initialize filesystem timestamp ranges

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-4f04b2fd1d2bSigned-off-by: default avatarDeepa Dinamani <deepa.kernel@gmail.com>
Acked-by: default avatarJeff Layton <jlayton@kernel.org>
Cc: sfrench@samba.org
Cc: linux-cifs@vger.kernel.org
parent 1fcb79c1
......@@ -56,6 +56,15 @@
#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;
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment