aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2024-04-26 00:13:03 -0400
committerTheodore Ts'o <tytso@mit.edu>2024-04-26 00:13:03 -0400
commitf590d7143b89ef33b1719595ac55785ad6d90bd7 (patch)
tree16e3143283ffefe8c1ae2849ba023c98fc301bb8
parent8cfc832cf6771c950c9220b6fe8c9df82f577c52 (diff)
downloade2fsprogs-f590d7143b89ef33b1719595ac55785ad6d90bd7.tar.gz
Prevent i_dtime from being mistaken for an inode number post-2038 wraparound
We explicitly decided not to reserve space for a 64-bit dtime, since it's never displayed or exposed to userspace. The dtime field is used a linked list for the ophan list, and for forensic purposes when trying to determine when an inode was deleted. So right after the 2038 epoch, a deleted inode might end up with a dtime which is zero or smaller than the number of inodes, which will result in e2fsck reporting a potential problems. So when we set the dtime, make sure that the dtime won't be mistaken for an inode number. Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--debugfs/debugfs.c2
-rw-r--r--e2fsck/journal.c2
-rw-r--r--e2fsck/pass1.c4
-rw-r--r--e2fsck/super.c2
-rw-r--r--lib/ext2fs/ext2fs.h24
-rw-r--r--lib/ext2fs/ext_attr.c2
-rw-r--r--lib/support/quotaio.c2
-rw-r--r--misc/create_inode_libarchive.c2
-rw-r--r--misc/fuse2fs.c2
9 files changed, 33 insertions, 9 deletions
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 16a03d48e..909c1df39 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -1876,7 +1876,7 @@ static void kill_file_by_inode(ext2_ino_t inode)
if (debugfs_read_inode(inode, &inode_buf, 0))
return;
- inode_buf.i_dtime = current_fs->now ? current_fs->now : time(0);
+ ext2fs_set_dtime(current_fs, &inode_buf);
if (debugfs_write_inode(inode, &inode_buf, 0))
return;
if (ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf)) {
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index 0144aa45a..19d68b430 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -1844,7 +1844,7 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
ext2fs_mark_super_dirty(fs);
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
inode.i_links_count = 0;
- inode.i_dtime = ctx->now;
+ ext2fs_set_dtime(fs, &inode);
if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
goto err_out;
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 078bcb9bf..8b6238e84 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1483,7 +1483,7 @@ void e2fsck_pass1(e2fsck_t ctx)
if (!inode->i_dtime && inode->i_mode) {
if (fix_problem(ctx,
PR_1_ZERO_DTIME, &pctx)) {
- inode->i_dtime = ctx->now;
+ ext2fs_set_dtime(fs, inode);
e2fsck_write_inode(ctx, ino, inode,
"pass1");
failed_csum = 0;
@@ -2793,7 +2793,7 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
inode->i_flags = 0;
inode->i_links_count = 0;
ext2fs_icount_store(ctx->inode_link_info, ino, 0);
- inode->i_dtime = ctx->now;
+ ext2fs_set_dtime(ctx->fs, inode);
/*
* If a special inode has such rotten block mappings that we
diff --git a/e2fsck/super.c b/e2fsck/super.c
index 051dc963a..60c690c22 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -348,7 +348,7 @@ static int release_orphan_inode(e2fsck_t ctx, ext2_ino_t *ino, char *block_buf)
ext2fs_inode_alloc_stats2(fs, *ino, -1,
LINUX_S_ISDIR(inode.i_mode));
ctx->free_inodes++;
- inode.i_dtime = ctx->now;
+ ext2fs_set_dtime(fs, EXT2_INODE(&inode));
} else {
inode.i_dtime = 0;
}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index c2638b803..6e87829fe 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -2301,6 +2301,30 @@ static inline unsigned int ext2_dir_htree_level(ext2_filsys fs)
return EXT4_HTREE_LEVEL_COMPAT;
}
+/*
+ * We explicitly decided not to reserve space for a 64-bit dtime,
+ * since it's never displayed or exposed to userspace. The dtime
+ * field is used a linked list for the ophan list, and for forensic
+ * purposes when trying to determine when an inode was deleted. So
+ * right after the 2038 epoch, a deleted inode might end up with a
+ * dtime which is zero or smaller than the number of inodes, which
+ * will result in e2fsck reporting a potential problems. So when we
+ * set the dtime, make sure that the dtime won't be mistaken for an
+ * inode number.
+ */
+static inline void ext2fs_set_dtime(ext2_filsys fs, struct ext2_inode *inode)
+{
+ __u32 t;
+
+ if (fs->now || (fs->flags2 & EXT2_FLAG2_USE_FAKE_TIME))
+ t = fs->now & 0xFFFFFFFF;
+ else
+ t = time(NULL) & 0xFFFFFFFF;
+ if (t < fs->super->s_inodes_count)
+ t = fs->super->s_inodes_count;
+ inode->i_dtime = t;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c
index b33bcce39..1b5f90d33 100644
--- a/lib/ext2fs/ext_attr.c
+++ b/lib/ext2fs/ext_attr.c
@@ -1342,7 +1342,7 @@ static errcode_t xattr_inode_dec_ref(ext2_filsys fs, ext2_ino_t ino)
goto write_out;
inode.i_links_count = 0;
- inode.i_dtime = ext2fsP_get_time(fs);
+ ext2fs_set_dtime(fs, EXT2_INODE(&inode));
ret = ext2fs_free_ext_attr(fs, ino, &inode);
if (ret)
diff --git a/lib/support/quotaio.c b/lib/support/quotaio.c
index 916e28cf5..f5f2c7f72 100644
--- a/lib/support/quotaio.c
+++ b/lib/support/quotaio.c
@@ -119,7 +119,7 @@ errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino)
break;
if (qtype != MAXQUOTAS) {
- inode.i_dtime = fs->now ? fs->now : time(0);
+ ext2fs_set_dtime(fs, &inode);
if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
return 0;
err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL);
diff --git a/misc/create_inode_libarchive.c b/misc/create_inode_libarchive.c
index d7822d8af..6ca0f9f2c 100644
--- a/misc/create_inode_libarchive.c
+++ b/misc/create_inode_libarchive.c
@@ -237,7 +237,7 @@ static int remove_inode(ext2_filsys fs, ext2_ino_t ino)
return 0; /* XXX: already done? */
case 1:
inode.i_links_count--;
- inode.i_dtime = fs->now ? fs->now : time(0);
+ ext2fs_set_dtime(fs, EXT2_INODE(&inode));
break;
default:
inode.i_links_count--;
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 6b2e727e4..5927fdf98 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -1243,7 +1243,7 @@ static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
return 0; /* XXX: already done? */
case 1:
inode.i_links_count--;
- inode.i_dtime = fs->now ? fs->now : time(0);
+ ext2fs_set_dtime(fs, EXT2_INODE(&inode));
break;
default:
inode.i_links_count--;