From: "Theodore Ts'o" <tytso@mit.edu>
To: Ext4 Developers List <linux-ext4@vger.kernel.org>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Subject: [PATCH 15/27] ext4: check multi-block overlap on left traversal in add_system_zone()
Date: Wed, 11 Nov 2026 23:06:26 -0500 [thread overview]
Message-ID: <20261112040638.1576836-16-tytso@mit.edu> (raw)
In-Reply-To: <20261112040638.1576836-1-tytso@mit.edu>
When walking system_blks->root to insert [start_blk, start_blk + count),
add_system_zone() takes the left branch whenever start_blk <
entry->start_blk instead of checking that the entire range ends at or
before entry->start_blk (unlike ext4_sb_block_valid(), which checks
start_blk + count - 1 < entry->start_blk).
As a result, a corrupt multi-block metadata range (such as a group's
inode table or a reserved journal inode extent mapped in
ext4_protect_reserved_inode() before sbi->s_system_blks is published)
that starts strictly before an existing system zone and extends into or
across it traverses rb_left instead of returning -EFSCORRUPTED. This
inserts overlapping intervals into system_blks->root and breaks the
disjoint-interval invariant relied upon by ext4_sb_block_valid() (for
example, a lookup on blocks past entry->start_blk + entry->count
branches right and misses the overlapping zone stored in rb_left). A
corrupt 64-bit start_blk whose start_blk + count wraps around u64 can
similarly corrupt the rbtree ordering.
Reject zero-length or u64-wrapping ranges up front and require
start_blk + count <= entry->start_blk before taking rb_left in
add_system_zone(). Add KUnit regression tests in
fs/ext4/block_validity-test.c covering group metadata and journal
extents that partially overlap from the left, completely enclose an
existing system zone, or wrap 64-bit block numbers.
Fixes: bf9a379d0980 ("ext4: don't allow overlapping system zones")
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
fs/ext4/block_validity-test.c | 68 +++++++++++++++++++++++++++++++++++
fs/ext4/block_validity.c | 5 ++-
2 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/block_validity-test.c b/fs/ext4/block_validity-test.c
index 5d3dadba1328..5b50f56b3453 100644
--- a/fs/ext4/block_validity-test.c
+++ b/fs/ext4/block_validity-test.c
@@ -1111,6 +1111,27 @@ static const struct bv_corrupt_meta_case bv_corrupt_meta_cases[] = {
.ibitmap = 2050,
.itable = 2051,
},
+ {
+ .desc = "itable_starts_before_and_overlaps_bbitmap",
+ .grp = 0,
+ .bbitmap = 20,
+ .ibitmap = 40,
+ .itable = 15,
+ },
+ {
+ .desc = "itable_starts_before_and_encloses_ibitmap",
+ .grp = 2,
+ .bbitmap = 50,
+ .ibitmap = 55,
+ .itable = 52,
+ },
+ {
+ .desc = "itable_u64_wrap_around_overflow",
+ .grp = 2,
+ .bbitmap = 2049,
+ .ibitmap = 2050,
+ .itable = U64_MAX - 2ULL,
+ },
};
KUNIT_ARRAY_PARAM_DESC(bv_corrupt_meta, bv_corrupt_meta_cases, desc);
@@ -1314,6 +1335,52 @@ static void test_journal_inode_overlap_sets_fs_error(struct kunit *test)
KUNIT_EXPECT_NULL(test, rcu_access_pointer(ctx->sbi.s_system_blks));
}
+static void test_journal_extent_left_overlap_rejected(struct kunit *test)
+{
+ struct bv_test_ctx *ctx = test->priv;
+ struct inode *j_inode;
+
+ /*
+ * Place group 2's block bitmap at block 20 (ino = 0) and map a
+ * multi-block journal extent at [18..21] that starts strictly before
+ * block 20 and extends across it. During ext4_setup_system_zone(),
+ * s_system_blks is still NULL when ext4_map_blocks() runs, so
+ * add_system_zone() must catch this left-traversal overlap.
+ */
+ bv_set_group_meta(ctx->sb, &ctx->gdps[2], 20ULL, 2050ULL, 2051ULL);
+ ext4_set_feature_journal(ctx->sb);
+ ctx->es.s_journal_inum = cpu_to_le32(EXT4_JOURNAL_INO);
+
+ j_inode = bv_create_inode(test, ctx, EXT4_JOURNAL_INO,
+ S_IFREG | 0600, true);
+ i_size_write(j_inode, 4 * BV_TEST_BLK_SIZE);
+ bv_append_extent(test, j_inode, 0, 18ULL, 4);
+
+ KUNIT_EXPECT_EQ(test, ext4_setup_system_zone(ctx->sb), -EFSCORRUPTED);
+ KUNIT_EXPECT_TRUE(test,
+ (bool)(ctx->sbi.s_mount_state & EXT4_ERROR_FS));
+ KUNIT_EXPECT_EQ(test, le32_to_cpu(ctx->es.s_last_error_ino),
+ (u32)EXT4_JOURNAL_INO);
+ KUNIT_EXPECT_EQ(test, ctx->es.s_last_error_errcode,
+ EXT4_ERR_EFSCORRUPTED);
+ KUNIT_EXPECT_NULL(test, rcu_access_pointer(ctx->sbi.s_system_blks));
+
+ /*
+ * Also verify a journal extent [1020..1040] that completely encloses
+ * group 1's entire metadata zone [1025..1038].
+ */
+ bv_clear_fs_error(ctx);
+ ext4_es_remove_extent(j_inode, 0, EXT_MAX_BLOCKS);
+ ext_inode_hdr(j_inode)->eh_entries = 0;
+ i_size_write(j_inode, 21 * BV_TEST_BLK_SIZE);
+ bv_append_extent(test, j_inode, 0, 1020ULL, 21);
+
+ KUNIT_EXPECT_EQ(test, ext4_setup_system_zone(ctx->sb), -EFSCORRUPTED);
+ KUNIT_EXPECT_TRUE(test,
+ (bool)(ctx->sbi.s_mount_state & EXT4_ERROR_FS));
+ KUNIT_EXPECT_NULL(test, rcu_access_pointer(ctx->sbi.s_system_blks));
+}
+
/* --- Test 10: ext4_check_blockref and Indirect Macros --- */
static void test_check_blockref_valid_and_sparse(struct kunit *test)
@@ -1498,6 +1565,7 @@ static struct kunit_case ext4_block_validity_test_cases[] = {
KUNIT_CASE(test_journal_inode_iget_error),
KUNIT_CASE(test_journal_inode_map_blocks_error),
KUNIT_CASE(test_journal_inode_overlap_sets_fs_error),
+ KUNIT_CASE(test_journal_extent_left_overlap_rejected),
KUNIT_CASE(test_check_blockref_valid_and_sparse),
KUNIT_CASE(test_check_blockref_corrupt_entries_and_journal_bypass),
KUNIT_CASE(test_ind_check_inode_and_indirect_blockref),
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
index 53b042f36a69..34468932e461 100644
--- a/fs/ext4/block_validity.c
+++ b/fs/ext4/block_validity.c
@@ -75,10 +75,13 @@ static int add_system_zone(struct ext4_system_blocks *system_blks,
struct rb_node **n = &system_blks->root.rb_node, *node;
struct rb_node *parent = NULL, *new_node;
+ if (!count || (start_blk + count < start_blk))
+ return -EFSCORRUPTED;
+
while (*n) {
parent = *n;
entry = rb_entry(parent, struct ext4_system_zone, node);
- if (start_blk < entry->start_blk)
+ if (start_blk + count <= entry->start_blk)
n = &(*n)->rb_left;
else if (start_blk >= (entry->start_blk + entry->count))
n = &(*n)->rb_right;
--
2.56.0.542.g3ef89b7020-goog
next prev parent reply other threads:[~2026-11-12 4:07 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 4:06 [PATCH 00/27] ext4: add lots of KUnit tests! Theodore Ts'o
2026-11-12 4:06 ` [PATCH 01/27] ext4: add KUinit tests for fs/ext4/extents_status.c Theodore Ts'o
2026-11-12 4:18 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 02/27] ext4: add KUnit tests for fs/ext4/extents.c Theodore Ts'o
2026-11-12 4:28 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 03/27] ext4: add KUnit tests for ext4_ext_split() leaf and index splitting Theodore Ts'o
2026-11-12 4:15 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 04/27] ext4: add KUnit tests for fs/ext4/xattr.c Theodore Ts'o
2026-11-12 4:26 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 05/27] ext4: add KUnit tests for fs/ext4/namei.c Theodore Ts'o
2026-11-12 4:21 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 06/27] ext4: expand KUnit tests for fs/ext4/mballoc.c Theodore Ts'o
2026-11-12 4:26 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 07/27] ext4: add KUnit tests for fs/ext4/inline.c Theodore Ts'o
2026-11-12 4:29 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 08/27] ext4: zero s_fc_replay_state in ext4_fc_replay_cleanup() Theodore Ts'o
2026-11-12 4:16 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 09/27] ext4: add KUnit tests for fs/ext4/fast_commit.c Theodore Ts'o
2026-11-12 4:28 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 10/27] ext4: expand KUnit tests for fs/ext4/inode.c Theodore Ts'o
2026-11-12 4:36 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 11/27] ext4: add KUnit tests for fs/ext4/ialloc.c Theodore Ts'o
2026-11-12 4:25 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 12/27] ext4: add KUnit tests for fs/ext4/balloc.c Theodore Ts'o
2026-11-12 4:16 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 13/27] ext4: add KUnit tests for fs/ext4/orphan.c Theodore Ts'o
2026-11-12 4:18 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 14/27] ext4: add KUnit tests for fs/ext4/block_validity.c Theodore Ts'o
2026-11-12 4:21 ` sashiko-bot
2026-11-12 4:06 ` Theodore Ts'o [this message]
2026-11-12 4:10 ` [PATCH 15/27] ext4: check multi-block overlap on left traversal in add_system_zone() sashiko-bot
2026-11-12 4:06 ` [PATCH 16/27] ext4: enable full feature coverage in fs/ext4/.kunitconfig Theodore Ts'o
2026-11-12 4:24 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 17/27] ext4: add KUnit tests for fs/ext4/super.c Theodore Ts'o
2026-11-12 4:27 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 18/27] ext4: add KUnit tests for fs/ext4/sysfs.c Theodore Ts'o
2026-11-12 4:32 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 19/27] ext4: add KUnit tests for fs/ext4/ioctl.c Theodore Ts'o
2026-11-12 4:35 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 20/27] ext4: add KUnit tests for fs/ext4/resize.c Theodore Ts'o
2026-11-12 4:34 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 21/27] ext4: add KUnit tests for fs/ext4/migrate.c Theodore Ts'o
2026-11-12 4:37 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 22/27] ext4: add KUnit tests for fs/ext4/indirect.c Theodore Ts'o
2026-11-12 4:46 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 23/27] ext4: expand KUnit tests in fs/ext4/extents-test.c for file range operations Theodore Ts'o
2026-11-12 4:34 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 24/27] ext4: add KUnit tests for fs/ext4/fsmap.c Theodore Ts'o
2026-11-12 4:30 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 25/27] ext4: add KUnit tests for fs/ext4/move_extent.c Theodore Ts'o
2026-11-12 4:36 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 26/27] ext4: add KUnit tests for fs/ext4/mmp.c Theodore Ts'o
2026-11-12 4:29 ` sashiko-bot
2026-11-12 4:06 ` [PATCH 27/27] ext4: add KUnit tests for fs/ext4/dir.c Theodore Ts'o
2026-11-12 4:41 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261112040638.1576836-16-tytso@mit.edu \
--to=tytso@mit.edu \
--cc=linux-ext4@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox