+ ocfs2-bound-check-dir-entries-in-the-inline-data-re-validation-scan.patch added to mm-nonmm-unstable branch

Andrew Morton <[email protected]>
Newsgroups org.kernel.vger.mm-commits
Message-ID <[email protected]>
The patch titled
     Subject: ocfs2: bound-check dir entries in the inline-data re-validation scan
has been added to the -mm mm-nonmm-unstable branch.  Its filename is
     ocfs2-bound-check-dir-entries-in-the-inline-data-re-validation-scan.patch

This patch will shortly appear at
     https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/ocfs2-bound-check-dir-entries-in-the-inline-data-re-validation-scan.patch

This patch will later appear in the mm-nonmm-unstable branch at
    git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***

The -mm tree is included into linux-next via various
branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
and is updated there most days

------------------------------------------------------
From: Zhan Xusheng <[email protected]>
Subject: ocfs2: bound-check dir entries in the inline-data re-validation scan
Date: Tue, 11 Aug 2026 10:43:37 +0800

ocfs2_dir_foreach_blk_id() re-scans the inline data area the same way
ocfs2_dir_foreach_blk_el() re-scans a directory block, and is missing the
same two bounds:

	for (i = 0; i < i_size_read(inode) && i < offset; ) {
		de = (struct ocfs2_dir_entry *)(data->id_data + i);
		if (le16_to_cpu(de->rec_len) < OCFS2_DIR_REC_LEN(1))
			break;
		i += le16_to_cpu(de->rec_len);
	}

ocfs2_validate_inode_block() keeps i_size inside the inline area:

	if (le16_to_cpu(data->id_count) >
	    ocfs2_max_inline_data_with_xattr(sb, di))
	if (le64_to_cpu(di->i_size) > le16_to_cpu(data->id_count))

and that area runs to the end of the inode block, so for a full inline
directory data->id_data + i_size is the end of di_bh->b_data.  A bogus
rec_len leaves i in the last OCFS2_DIR_REC_LEN(1) - 1 bytes of it, and
de->rec_len, at byte offset 8 within the entry, is then read past the
block.

The emit loop below hands i_size_read(inode) to ocfs2_check_dir_entry(),
which refuses both an entry that close to the end and one whose rec_len
runs past it.  Apply the same two bounds to the re-validation scan,
reading i_size once into a local as ocfs2_check_dir_entry() takes it as
@size.

Unlike the extent case there is no mask to corrupt here: an unbounded i
only sets ctx->pos past i_size, which ends the readdir early rather than
moving it to the wrong place.

Link: https://lore.kernel.org/[email protected]
Signed-off-by: Zhan Xusheng <[email protected]>
Reviewed-by: Joseph Qi <[email protected]>
Cc: Mark Fasheh <[email protected]>
Cc: Joel Becker <[email protected]>
Cc: Junxiao Bi <[email protected]>
Cc: Changwei Ge <[email protected]>
Cc: Jun Piao <[email protected]>
Cc: Heming Zhao <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
---

 fs/ocfs2/dir.c |   14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

--- a/fs/ocfs2/dir.c~ocfs2-bound-check-dir-entries-in-the-inline-data-re-validation-scan
+++ a/fs/ocfs2/dir.c
@@ -1849,7 +1849,12 @@ static int ocfs2_dir_foreach_blk_id(stru
 		 * dirent right now.  Scan from the start of the block
 		 * to make sure. */
 		if (!inode_eq_iversion(inode, *f_version)) {
-			for (i = 0; i < i_size_read(inode) && i < offset; ) {
+			loff_t size = i_size_read(inode);
+
+			for (i = 0; i + OCFS2_DIR_REC_LEN(1) <= size &&
+			     i < offset;) {
+				unsigned int rec_len;
+
 				de = (struct ocfs2_dir_entry *)
 					(data->id_data + i);
 				/* It's too expensive to do a full
@@ -1858,10 +1863,11 @@ static int ocfs2_dir_foreach_blk_id(stru
 				 * least that it is non-zero.  A
 				 * failure will be detected in the
 				 * dirent test below. */
-				if (le16_to_cpu(de->rec_len) <
-				    OCFS2_DIR_REC_LEN(1))
+				rec_len = le16_to_cpu(de->rec_len);
+				if (rec_len < OCFS2_DIR_REC_LEN(1) ||
+				    i + rec_len > size)
 					break;
-				i += le16_to_cpu(de->rec_len);
+				i += rec_len;
 			}
 			ctx->pos = offset = i;
 			*f_version = inode_query_iversion(inode);
_

Patches currently in -mm which might be from [email protected] are

maple_tree-remove-unused-mas_is_root_limits.patch
ocfs2-fix-readdir-position-truncation-on-32-bit-kernels.patch
ocfs2-bound-check-dir-entries-in-the-readdir-re-validation-scan.patch
ocfs2-bound-check-dir-entries-in-the-inline-data-re-validation-scan.patch
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.