]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Prevent i_dtime from being mistaken for an inode number post-2038 wraparound
authorTheodore Ts'o <tytso@mit.edu>
Fri, 26 Apr 2024 04:13:03 +0000 (00:13 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 26 Apr 2024 04:13:03 +0000 (00:13 -0400)
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>
debugfs/debugfs.c
e2fsck/journal.c
e2fsck/pass1.c
e2fsck/super.c
lib/ext2fs/ext2fs.h
lib/ext2fs/ext_attr.c
lib/support/quotaio.c
misc/create_inode_libarchive.c
misc/fuse2fs.c

index 16a03d48e9a87ba5154218e58b5f0e639ae90734..909c1df39bbf1fc27f1e2c5c306e338f75587f34 100644 (file)
@@ -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)) {
index 0144aa45aa90ddb50cfaf6801131675038bc1901..19d68b4306ba0bbba716080769a044cc45376626 100644 (file)
@@ -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;
 
index 078bcb9bfe4ce2ce7d64d22de63c2dcd083b1948..8b6238e8434c825dbd0b37e03f8224a8f12746e0 100644 (file)
@@ -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
index 051dc963acfe0dcb9a5c4784d8e5450c7e107ff2..60c690c227c232f3c4641541fbafba7f1ff4d75a 100644 (file)
@@ -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;
        }
index c2638b8037b2d5635d9b7383f84249bedbdc6c12..6e87829fe49eb1d39ba0260987b0bfbf8f4fb913 100644 (file)
@@ -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
index b33bcce3995f06ced551f28479324fb628792e44..1b5f90d33f3cd45ec1408f5f087fe00c9d898ec0 100644 (file)
@@ -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)
index 916e28cf50f1e890e6b0e1699823aa3b56cc52ee..f5f2c7f72da8ff770642f3972ee6d0cb21bb2d0d 100644 (file)
@@ -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);
index d7822d8affb71bf93f95df5474210af8903eb675..6ca0f9f2c1d3ee7255a1756afed6cb95c2baf53d 100644 (file)
@@ -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--;
index 6b2e727e4cd0f885bb6491d8f89ccd469d8fe010..5927fdf98cb5d29dccf6c4c4219ce9a352b3ec39 100644 (file)
@@ -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--;