lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <174553065069.1160461.14751120886781323020.stgit@frogsfrogsfrogs>
Date: Thu, 24 Apr 2025 14:42:52 -0700
From: "Darrick J. Wong" <djwong@...nel.org>
To: tytso@....edu
Cc: linux-ext4@...r.kernel.org
Subject: [PATCH 08/16] fuse2fs: clamp timestamps that are being written to
 disk

From: Darrick J. Wong <djwong@...nel.org>

Clamp the timestamps that we write to disk to the minimum and maximum
values permitted given the ondisk format.  This fixes y2038 support, as
tested by generic/402.

Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
---
 lib/ext2fs/ext2_fs.h |    4 ++++
 misc/fuse2fs.c       |   39 ++++++++++++++++++++++++++++++++-------
 2 files changed, 36 insertions(+), 7 deletions(-)


diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 3a5eb7387d0c9d..fcd42055665788 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -801,6 +801,10 @@ struct ext2_super_block {
 
 #define EXT2_GOOD_OLD_INODE_SIZE 128
 
+#define EXT4_EXTRA_TIMESTAMP_MAX	(((int64_t)1 << 34) - 1  + INT32_MIN)
+#define EXT4_NON_EXTRA_TIMESTAMP_MAX	INT32_MAX
+#define EXT4_TIMESTAMP_MIN		INT32_MIN
+
 /*
  * Journal inode backup types
  */
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index bf4e592e7d2782..9cf8c59b8b88ee 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -227,21 +227,43 @@ static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra)
 	time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
 }
 
+#define EXT4_CLAMP_TIMESTAMP(xtime, timespec, raw_inode)		       \
+do {									       \
+	if ((timespec)->tv_sec < EXT4_TIMESTAMP_MIN)			       \
+		(timespec)->tv_sec = EXT4_TIMESTAMP_MIN;		       \
+	if ((timespec)->tv_sec < EXT4_TIMESTAMP_MIN)			       \
+		(timespec)->tv_sec = EXT4_TIMESTAMP_MIN;		       \
+									       \
+	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) {		       \
+		if ((timespec)->tv_sec > EXT4_EXTRA_TIMESTAMP_MAX)	       \
+			(timespec)->tv_sec = EXT4_EXTRA_TIMESTAMP_MAX;	       \
+	} else {							       \
+		if ((timespec)->tv_sec > EXT4_NON_EXTRA_TIMESTAMP_MAX)	       \
+			(timespec)->tv_sec = EXT4_NON_EXTRA_TIMESTAMP_MAX;     \
+	}								       \
+} while (0)
+
 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode)		       \
 do {									       \
-	(raw_inode)->xtime = (timespec)->tv_sec;			       \
+	typeof(*(timespec)) _ts = *(timespec);				       \
+									       \
+	EXT4_CLAMP_TIMESTAMP(xtime, &_ts, raw_inode);			       \
+	(raw_inode)->xtime = _ts.tv_sec;				       \
 	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))		       \
 		(raw_inode)->xtime ## _extra =				       \
-				ext4_encode_extra_time(timespec);	       \
+				ext4_encode_extra_time(&_ts);		       \
 } while (0)
 
 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode)		       \
 do {									       \
+	typeof(*(timespec)) _ts = *(timespec);				       \
+									       \
+	EXT4_CLAMP_TIMESTAMP(xtime, &_ts, raw_inode);			       \
 	if (EXT4_FITS_IN_INODE(raw_inode, xtime))			       \
-		(raw_inode)->xtime = (timespec)->tv_sec;		       \
+		(raw_inode)->xtime = _ts.tv_sec;			       \
 	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))		       \
 		(raw_inode)->xtime ## _extra =				       \
-				ext4_encode_extra_time(timespec);	       \
+				ext4_encode_extra_time(&_ts);		       \
 } while (0)
 
 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode)		       \
@@ -2884,7 +2906,10 @@ static int op_utimens(const char *path, const struct timespec ctv[2]
 		ret = translate_error(fs, 0, err);
 		goto out;
 	}
-	dbg_printf(ff, "%s: ino=%d\n", __func__, ino);
+	dbg_printf(ff, "%s: ino=%d atime=%lld.%ld mtime=%lld.%ld\n", __func__,
+			ino,
+			(long long int)ctv[0].tv_sec, ctv[0].tv_nsec,
+			(long long int)ctv[1].tv_sec, ctv[1].tv_nsec);
 
 	ret = check_inum_access(fs, ino, W_OK);
 	if (ret)
@@ -2908,9 +2933,9 @@ static int op_utimens(const char *path, const struct timespec ctv[2]
 #endif /* UTIME_NOW */
 #ifdef UTIME_OMIT
 	if (tv[0].tv_nsec != UTIME_OMIT)
-		EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
+		EXT4_INODE_SET_XTIME(i_atime, &tv[0], &inode);
 	if (tv[1].tv_nsec != UTIME_OMIT)
-		EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
+		EXT4_INODE_SET_XTIME(i_mtime, &tv[1], &inode);
 #endif /* UTIME_OMIT */
 	ret = update_ctime(fs, ino, &inode);
 	if (ret)


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ