* FAILED: patch "[PATCH] ocfs2: validate directory-index entry counts when reading" failed to apply to 6.6-stable tree
@ 2026-09-03 14:29 gregkh
2026-09-09 10:34 ` [PATCH 6.6.y 1/2] ocfs2: validate dx_root extent list fields during block read Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: gregkh @ 2026-09-03 14:29 UTC (permalink / raw)
To: doruk, akpm, gechangwei, heming.zhao, jlbec, joseph.qi,
junxiao.bi, kees, mark, piaojun, stable
Cc: stable
The patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x bc70726ddad53c7e9a9a85915bf2415b0d4f42f9
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090340-lecturer-unwashed-3c35@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From bc70726ddad53c7e9a9a85915bf2415b0d4f42f9 Mon Sep 17 00:00:00 2001
From: Doruk Tan Ozturk <doruk@0sec.ai>
Date: Mon, 13 Jul 2026 22:56:25 +0200
Subject: [PATCH] ocfs2: validate directory-index entry counts when reading
metadata
ocfs2_validate_dx_leaf() and ocfs2_validate_dx_root() check the ECC and
signature of an indexed-directory block before it reaches higher-level
callers, but neither validator bounds the ocfs2_dx_entry_list counts
against the capacity of the block that holds them.
ocfs2_dx_dir_search() then walks
for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++)
dx_entry = &entry_list->de_entries[i];
over de_num_used entries with no bounds check. entry_list is either
dx_leaf->dl_list (from ocfs2_read_dx_leaf) or, for an inline root,
dx_root->dr_entries. A crafted on-disk image can set de_num_used (and
de_count, which is the __counted_by_le() bound of de_entries) to 0xffff
and make the walk read far past the end of the 4KB metadata block, giving
a slab out-of-bounds read reachable from any path lookup, stat() or open()
on an indexed directory once the image is mounted.
Commit 775c17386a6f ("ocfs2: validate dx_root extent list fields during
block read") already bounds dr_list for the non-inline dx_root, but left
the inline dr_entries path and the dx_leaf dl_list unchecked. Add the
same read-time validation for both entry lists: de_count must equal the
capacity of the block (ocfs2_dx_entries_per_leaf()/per_root()) and
de_num_used must not exceed de_count, rejecting corrupted metadata with
-EFSCORRUPTED before ocfs2_dx_dir_search() can walk an out-of-range entry
array.
de_count is always written as exactly the block capacity when a leaf or
inline root is formatted, so the equality check does not reject any valid
image.
Found by 0sec automated security-research tooling (https://0sec.ai).
Link: https://lore.kernel.org/20260713205625.92391-1-doruk@0sec.ai
Fixes: 9b7895efac90 ("ocfs2: Add a name indexed b-tree to directory inodes")
Fixes: 4ed8a6bb083b ("ocfs2: Store dir index records inline")
Assisted-by: 0sec:claude-opus-4-8
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 047d1b486f4a..7e09a5a4d49e 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -625,6 +625,28 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
le16_to_cpu(el->l_count));
goto bail;
}
+ } else {
+ struct ocfs2_dx_entry_list *dl_list = &dx_root->dr_entries;
+
+ if (le16_to_cpu(dl_list->de_count) !=
+ ocfs2_dx_entries_per_root(sb)) {
+ ret = ocfs2_error(sb,
+ "Dir Index Root # %llu has invalid de_count %u (expected %u)\n",
+ (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+ le16_to_cpu(dl_list->de_count),
+ ocfs2_dx_entries_per_root(sb));
+ goto bail;
+ }
+
+ if (le16_to_cpu(dl_list->de_num_used) >
+ le16_to_cpu(dl_list->de_count)) {
+ ret = ocfs2_error(sb,
+ "Dir Index Root # %llu has invalid de_num_used %u (de_count %u)\n",
+ (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+ le16_to_cpu(dl_list->de_num_used),
+ le16_to_cpu(dl_list->de_count));
+ goto bail;
+ }
}
bail:
@@ -664,10 +686,25 @@ static int ocfs2_validate_dx_leaf(struct super_block *sb,
return ret;
}
- 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);
- }
+ if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf))
+ return ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s\n",
+ 7, dx_leaf->dl_signature);
+
+ if (le16_to_cpu(dx_leaf->dl_list.de_count) !=
+ ocfs2_dx_entries_per_leaf(sb))
+ return ocfs2_error(sb,
+ "Dir Index Leaf # %llu has invalid de_count %u (expected %u)\n",
+ (unsigned long long)le64_to_cpu(dx_leaf->dl_blkno),
+ le16_to_cpu(dx_leaf->dl_list.de_count),
+ ocfs2_dx_entries_per_leaf(sb));
+
+ if (le16_to_cpu(dx_leaf->dl_list.de_num_used) >
+ le16_to_cpu(dx_leaf->dl_list.de_count))
+ return ocfs2_error(sb,
+ "Dir Index Leaf # %llu has invalid de_num_used %u (de_count %u)\n",
+ (unsigned long long)le64_to_cpu(dx_leaf->dl_blkno),
+ le16_to_cpu(dx_leaf->dl_list.de_num_used),
+ le16_to_cpu(dx_leaf->dl_list.de_count));
return ret;
}
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 6.6.y 1/2] ocfs2: validate dx_root extent list fields during block read
2026-09-03 14:29 FAILED: patch "[PATCH] ocfs2: validate directory-index entry counts when reading" failed to apply to 6.6-stable tree gregkh
@ 2026-09-09 10:34 ` Sasha Levin
2026-09-09 10:34 ` [PATCH 6.6.y 2/2] ocfs2: validate directory-index entry counts when reading metadata Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-09-09 10:34 UTC (permalink / raw)
To: stable
Cc: Joseph Qi, Heming Zhao, Mark Fasheh, Joel Becker, Junxiao Bi,
Changwei Ge, Jun Piao, Andrew Morton, Sasha Levin
From: Joseph Qi <joseph.qi@linux.alibaba.com>
[ Upstream commit 775c17386a6fd695f999d4cda90e3931386570dd ]
Patch series "ocfs2: consolidate extent list validation into block read
callbacks".
ocfs2 validates extent list fields (l_count, l_next_free_rec) at various
points during extent tree traversal. This is fragile because each caller
must remember to check for corrupted on-disk data before using it.
This series moves those checks into the block read validation callbacks
(ocfs2_validate_dx_root and ocfs2_validate_extent_block), so corrupted
fields are caught early at block read time. Redundant post-read checks
are then removed.
This patch (of 4):
Move the extent list l_count validation from ocfs2_dx_dir_lookup_rec()
into ocfs2_validate_dx_root(), so that corrupted on-disk fields are caught
early at block read time rather than during directory lookups.
Additionally, add a l_next_free_rec <= l_count check to prevent
out-of-bounds access when iterating over extent records.
Both checks are skipped for inline dx roots (OCFS2_DX_FLAG_INLINE), which
use dr_entries instead of dr_list.
Link: https://lkml.kernel.org/r/20260403090803.3860971-1-joseph.qi@linux.alibaba.com
Link: https://lkml.kernel.org/r/20260403090803.3860971-2-joseph.qi@linux.alibaba.com
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: bc70726ddad5 ("ocfs2: validate directory-index entry counts when reading metadata")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/dir.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index da1ab3282c181..b706092c0c1b4 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -580,7 +580,7 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
mlog(ML_ERROR,
"Checksum failed for dir index root block %llu\n",
(unsigned long long)bh->b_blocknr);
- return ret;
+ goto bail;
}
if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) {
@@ -588,8 +588,32 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
"Dir Index Root # %llu has bad signature %.*s\n",
(unsigned long long)le64_to_cpu(dx_root->dr_blkno),
7, dx_root->dr_signature);
+ goto bail;
+ }
+
+ if (!(dx_root->dr_flags & OCFS2_DX_FLAG_INLINE)) {
+ struct ocfs2_extent_list *el = &dx_root->dr_list;
+
+ if (le16_to_cpu(el->l_count) != ocfs2_extent_recs_per_dx_root(sb)) {
+ ret = ocfs2_error(sb,
+ "Dir Index Root # %llu has invalid l_count %u (expected %u)\n",
+ (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+ le16_to_cpu(el->l_count),
+ ocfs2_extent_recs_per_dx_root(sb));
+ goto bail;
+ }
+
+ if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) {
+ ret = ocfs2_error(sb,
+ "Dir Index Root # %llu has invalid l_next_free_rec %u (l_count %u)\n",
+ (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+ le16_to_cpu(el->l_next_free_rec),
+ le16_to_cpu(el->l_count));
+ goto bail;
+ }
}
+bail:
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 6.6.y 2/2] ocfs2: validate directory-index entry counts when reading metadata
2026-09-09 10:34 ` [PATCH 6.6.y 1/2] ocfs2: validate dx_root extent list fields during block read Sasha Levin
@ 2026-09-09 10:34 ` Sasha Levin
0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-09-09 10:34 UTC (permalink / raw)
To: stable
Cc: Doruk Tan Ozturk, Joseph Qi, Joel Becker, Kees Cook, Mark Fasheh,
Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao, Andrew Morton,
Sasha Levin
From: Doruk Tan Ozturk <doruk@0sec.ai>
[ Upstream commit bc70726ddad53c7e9a9a85915bf2415b0d4f42f9 ]
ocfs2_validate_dx_leaf() and ocfs2_validate_dx_root() check the ECC and
signature of an indexed-directory block before it reaches higher-level
callers, but neither validator bounds the ocfs2_dx_entry_list counts
against the capacity of the block that holds them.
ocfs2_dx_dir_search() then walks
for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++)
dx_entry = &entry_list->de_entries[i];
over de_num_used entries with no bounds check. entry_list is either
dx_leaf->dl_list (from ocfs2_read_dx_leaf) or, for an inline root,
dx_root->dr_entries. A crafted on-disk image can set de_num_used (and
de_count, which is the __counted_by_le() bound of de_entries) to 0xffff
and make the walk read far past the end of the 4KB metadata block, giving
a slab out-of-bounds read reachable from any path lookup, stat() or open()
on an indexed directory once the image is mounted.
Commit 775c17386a6f ("ocfs2: validate dx_root extent list fields during
block read") already bounds dr_list for the non-inline dx_root, but left
the inline dr_entries path and the dx_leaf dl_list unchecked. Add the
same read-time validation for both entry lists: de_count must equal the
capacity of the block (ocfs2_dx_entries_per_leaf()/per_root()) and
de_num_used must not exceed de_count, rejecting corrupted metadata with
-EFSCORRUPTED before ocfs2_dx_dir_search() can walk an out-of-range entry
array.
de_count is always written as exactly the block capacity when a leaf or
inline root is formatted, so the equality check does not reject any valid
image.
Found by 0sec automated security-research tooling (https://0sec.ai).
Link: https://lore.kernel.org/20260713205625.92391-1-doruk@0sec.ai
Fixes: 9b7895efac90 ("ocfs2: Add a name indexed b-tree to directory inodes")
Fixes: 4ed8a6bb083b ("ocfs2: Store dir index records inline")
Assisted-by: 0sec:claude-opus-4-8
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/dir.c | 45 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 41 insertions(+), 4 deletions(-)
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index b706092c0c1b4..d9cd7b396c8eb 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -611,6 +611,28 @@ static int ocfs2_validate_dx_root(struct super_block *sb,
le16_to_cpu(el->l_count));
goto bail;
}
+ } else {
+ struct ocfs2_dx_entry_list *dl_list = &dx_root->dr_entries;
+
+ if (le16_to_cpu(dl_list->de_count) !=
+ ocfs2_dx_entries_per_root(sb)) {
+ ret = ocfs2_error(sb,
+ "Dir Index Root # %llu has invalid de_count %u (expected %u)\n",
+ (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+ le16_to_cpu(dl_list->de_count),
+ ocfs2_dx_entries_per_root(sb));
+ goto bail;
+ }
+
+ if (le16_to_cpu(dl_list->de_num_used) >
+ le16_to_cpu(dl_list->de_count)) {
+ ret = ocfs2_error(sb,
+ "Dir Index Root # %llu has invalid de_num_used %u (de_count %u)\n",
+ (unsigned long long)le64_to_cpu(dx_root->dr_blkno),
+ le16_to_cpu(dl_list->de_num_used),
+ le16_to_cpu(dl_list->de_count));
+ goto bail;
+ }
}
bail:
@@ -650,10 +672,25 @@ static int ocfs2_validate_dx_leaf(struct super_block *sb,
return ret;
}
- 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);
- }
+ if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf))
+ return ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s\n",
+ 7, dx_leaf->dl_signature);
+
+ if (le16_to_cpu(dx_leaf->dl_list.de_count) !=
+ ocfs2_dx_entries_per_leaf(sb))
+ return ocfs2_error(sb,
+ "Dir Index Leaf # %llu has invalid de_count %u (expected %u)\n",
+ (unsigned long long)le64_to_cpu(dx_leaf->dl_blkno),
+ le16_to_cpu(dx_leaf->dl_list.de_count),
+ ocfs2_dx_entries_per_leaf(sb));
+
+ if (le16_to_cpu(dx_leaf->dl_list.de_num_used) >
+ le16_to_cpu(dx_leaf->dl_list.de_count))
+ return ocfs2_error(sb,
+ "Dir Index Leaf # %llu has invalid de_num_used %u (de_count %u)\n",
+ (unsigned long long)le64_to_cpu(dx_leaf->dl_blkno),
+ le16_to_cpu(dx_leaf->dl_list.de_num_used),
+ le16_to_cpu(dx_leaf->dl_list.de_count));
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-09 10:34 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 14:29 FAILED: patch "[PATCH] ocfs2: validate directory-index entry counts when reading" failed to apply to 6.6-stable tree gregkh
2026-09-09 10:34 ` [PATCH 6.6.y 1/2] ocfs2: validate dx_root extent list fields during block read Sasha Levin
2026-09-09 10:34 ` [PATCH 6.6.y 2/2] ocfs2: validate directory-index entry counts when reading metadata Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.