Whamcloud - gitweb
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 16a03d4..909c1df 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 0144aa4..19d68b4 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 078bcb9..8b6238e 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 051dc96..60c690c 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 c2638b8..6e87829 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 b33bcce..1b5f90d 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 916e28c..f5f2c7f 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 d7822d8..6ca0f9f 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 6b2e727..5927fdf 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--;