public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ocfs2: validate dx entry list counts on read
@ 2026-04-16  8:21 ZhengYuan Huang
  0 siblings, 0 replies; only message in thread
From: ZhengYuan Huang @ 2026-04-16  8:21 UTC (permalink / raw)
  To: mark, jlbec, joseph.qi
  Cc: ocfs2-devel, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
	ZhengYuan Huang

[BUG]
A corrupt indexed directory block can carry de_num_used larger than
de_count. When create() needs to rebalance the directory index, that
corrupt count reaches ocfs2_dx_dir_transfer_leaf() and trips fortify:

kernel BUG at lib/string_helpers.c:1043!
RIP: 0010:__fortify_panic+0x24/0x30 lib/string_helpers.c:1043
Call Trace:
 fortify_memset_chk include/linux/fortify-string.h:497 [inline]
 ocfs2_dx_dir_transfer_leaf fs/ocfs2/dir.c:3677 [inline]
 ocfs2_dx_dir_rebalance.isra.0+0x231a/0x24c0 fs/ocfs2/dir.c:3873
 ocfs2_find_dir_space_dx.isra.0+0x32c/0x5f0 fs/ocfs2/dir.c:3950
 ocfs2_prepare_dx_dir_for_insert.isra.0+0x750/0xf20 fs/ocfs2/dir.c:4207
 ocfs2_prepare_dir_for_insert+0xe79/0x1630 fs/ocfs2/dir.c:4288
 ocfs2_mknod+0x81c/0x2400 fs/ocfs2/namei.c:297
 ocfs2_create+0x158/0x390 fs/ocfs2/namei.c:676
 lookup_open.isra.0+0x10a1/0x1460 fs/namei.c:3796
 open_last_lookups fs/namei.c:3895 [inline]
 path_openat+0x11fe/0x2ce0 fs/namei.c:4131
 do_filp_open+0x1f6/0x430 fs/namei.c:4161
 do_sys_openat2+0x117/0x1c0 fs/open.c:1437
 do_sys_open fs/open.c:1452 [inline]
 __do_sys_openat fs/open.c:1468 [inline]
 __se_sys_openat fs/open.c:1463 [inline]
 __x64_sys_openat+0x15b/0x220 fs/open.c:1463
 ...

[CAUSE]
DX leaf and inline dx root blocks validate signatures and ECC, but they
do not validate the geometry of struct ocfs2_dx_entry_list. Corrupt
de_count/de_num_used values therefore survive block read and are later
used as traversal bounds and memset lengths in lookup, delete and
rebalance paths.

[FIX]
Validate dx entry-list geometry in the metadata read callbacks. de_count
must match the block layout for the current superblock, and de_num_used
must not exceed de_count. Do this for both dx leaves and inline dx
roots so corrupted metadata is rejected before any caller walks or
rewrites de_entries[].

Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
No Fixes tag is included because this is a missing metadata validation
check, not a regression attributable to a single introducing commit.
---
fs/ocfs2/dir.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 8e6b03238327..a89634e20b32 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -578,6 +578,29 @@ static int ocfs2_read_dir_block_direct(struct inode *dir, u64 phys,
 	return ret;
 }
 
+static int ocfs2_validate_dx_entry_list(struct super_block *sb, u64 blkno,
+					struct ocfs2_dx_entry_list *entry_list,
+					unsigned int expected,
+					const char *owner)
+{
+	unsigned int count = le16_to_cpu(entry_list->de_count);
+	unsigned int num_used = le16_to_cpu(entry_list->de_num_used);
+
+	if (count != expected)
+		return ocfs2_error(sb,
+				   "%s # %llu has invalid de_count %u (expected %u)\n",
+				   owner, (unsigned long long)blkno, count,
+				   expected);
+
+	if (num_used > count)
+		return ocfs2_error(sb,
+				   "%s # %llu has invalid de_num_used %u (de_count %u)\n",
+				   owner, (unsigned long long)blkno, num_used,
+				   count);
+
+	return 0;
+}
+
 static int ocfs2_validate_dx_root(struct super_block *sb,
 				  struct buffer_head *bh)
 {
@@ -604,7 +625,14 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
 		goto bail;
 	}
 
-	if (!(dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)) {
+	if (dx_root->dr_flags & OCFS2_DX_FLAG_INLINE) {
+		ret = ocfs2_validate_dx_entry_list(sb, bh->b_blocknr,
+						   &dx_root->dr_entries,
+						   ocfs2_dx_entries_per_root(sb),
+						   "Dir Index Root");
+		if (ret)
+			goto bail;
+	} else {
 		struct ocfs2_extent_list *el = &dx_root->dr_list;
 
 		if (le16_to_cpu(el->l_count) != ocfs2_extent_recs_per_dx_root(sb)) {
@@ -660,13 +688,21 @@ static int ocfs2_validate_dx_leaf(struct super_block *sb,
 		mlog(ML_ERROR,
 		     "Checksum failed for dir index leaf block %llu\n",
 		     (unsigned long long)bh->b_blocknr);
-		return ret;
+		goto bail;
 	}
 
 	if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf)) {
 		ret = ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s\n",
 				  7, dx_leaf->dl_signature);
+		goto bail;
 	}
 
+	ret = ocfs2_validate_dx_entry_list(sb, bh->b_blocknr,
+					   &dx_leaf->dl_list,
+					   ocfs2_dx_entries_per_leaf(sb),
+					   "Dir Index Leaf");
+
+bail:
+
 	return ret;
 }
-- 
2.43.0

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-04-16  8:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-16  8:21 [PATCH] ocfs2: validate dx entry list counts on read ZhengYuan Huang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox