From: Yu Kuai yukuai3@huawei.com
hulk inclusion category: bugfix bugzilla: 50526 CVE: NA ---------------------------
Inode atime/mtime is 64-bit, however xfs ondisk atime/mtime is 32-bit( supported range is from Dec 13 20:45:52 UTC 1901 to Jan 19 03:14:07 UTC 2038). Thus if in-memory atime/mtime overflow, after umount and mount, atime/mtime will be wrong.
In order to fix it, truncate atime/ctime/mtime in xfs_vn_setattr().
This problem was fixed in commit 22b139691f9e ("fs: Fill in max and min timestamps in superblock") from mainline, which relied on commit 50e17c000c46 ("vfs: Add timestamp_truncate() api") and commit 188d20bcd1eb ("vfs: Add file timestamp range support"). However, kabi will be broken if we backport these patches, thus we do local adaptation for xfs instead.
Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Cheng Jian cj.chengjian@huawei.com --- fs/xfs/libxfs/xfs_format.h | 12 ++++++++++++ fs/xfs/xfs_iops.c | 17 ++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index afbe336600e1..c63c27248d5e 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -832,6 +832,18 @@ typedef struct xfs_timestamp { __be32 t_nsec; /* timestamp nanoseconds */ } xfs_timestamp_t;
+/* + * Smallest possible ondisk seconds value with traditional timestamps. This + * corresponds exactly with the incore timestamp Dec 13 20:45:52 UTC 1901. + */ +#define XFS_LEGACY_TIME_MIN ((int64_t)S32_MIN) + +/* + * Largest possible ondisk seconds value with traditional timestamps. This + * corresponds exactly with the incore timestamp Jan 19 03:14:07 UTC 2038. + */ +#define XFS_LEGACY_TIME_MAX ((int64_t)S32_MAX) + /* * On-disk inode structure. * diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 948ac1290121..870e7b77b11c 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -584,6 +584,17 @@ xfs_setattr_mode( inode->i_mode |= mode & ~S_IFMT; }
+static inline struct timespec64 xfs_timestamp_truncate(struct timespec64 t) +{ + t.tv_sec = clamp(t.tv_sec, XFS_LEGACY_TIME_MIN, XFS_LEGACY_TIME_MAX); + + if (unlikely(t.tv_sec == XFS_LEGACY_TIME_MIN || + t.tv_sec == XFS_LEGACY_TIME_MAX)) + t.tv_sec = 0; + + return t; +} + void xfs_setattr_time( struct xfs_inode *ip, @@ -594,11 +605,11 @@ xfs_setattr_time( ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (iattr->ia_valid & ATTR_ATIME) - inode->i_atime = iattr->ia_atime; + inode->i_atime = xfs_timestamp_truncate(iattr->ia_atime); if (iattr->ia_valid & ATTR_CTIME) - inode->i_ctime = iattr->ia_ctime; + inode->i_ctime = xfs_timestamp_truncate(iattr->ia_ctime); if (iattr->ia_valid & ATTR_MTIME) - inode->i_mtime = iattr->ia_mtime; + inode->i_mtime = xfs_timestamp_truncate(iattr->ia_mtime); }
static int