diff options
author | Theodore Ts'o <tytso@mit.edu> | 2024-04-26 00:13:03 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2024-04-26 00:13:03 -0400 |
commit | f590d7143b89ef33b1719595ac55785ad6d90bd7 (patch) | |
tree | 16e3143283ffefe8c1ae2849ba023c98fc301bb8 | |
parent | 8cfc832cf6771c950c9220b6fe8c9df82f577c52 (diff) | |
download | e2fsprogs-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.c | 2 | ||||
-rw-r--r-- | e2fsck/journal.c | 2 | ||||
-rw-r--r-- | e2fsck/pass1.c | 4 | ||||
-rw-r--r-- | e2fsck/super.c | 2 | ||||
-rw-r--r-- | lib/ext2fs/ext2fs.h | 24 | ||||
-rw-r--r-- | lib/ext2fs/ext_attr.c | 2 | ||||
-rw-r--r-- | lib/support/quotaio.c | 2 | ||||
-rw-r--r-- | misc/create_inode_libarchive.c | 2 | ||||
-rw-r--r-- | misc/fuse2fs.c | 2 |
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--; |