* [PATCH] jfs: reject xtree pages whose BT_ROOT flag does not match
@ 2026-10-20 16:32 Nicholas Velten via B4 Relay
0 siblings, 0 replies; only message in thread
From: Nicholas Velten via B4 Relay @ 2026-10-20 16:32 UTC (permalink / raw)
To: Dave Kleikamp
Cc: jfs-discussion, linux-kernel, syzbot+43706fd1eb4c8dccdfe6,
Nicholas Velten
From: Nicholas Velten <nicholasfvelten@gmail.com>
syzbot reports a crash in release_metapage() when an inode from a
corrupted JFS image is evicted:
Oops: stack segment: 0000 [#1] SMP KASAN PTI
RIP: 0010:release_metapage+0x9e/0xab0 fs/jfs/jfs_metapage.c:870
Call Trace:
xtTruncate+0xecd/0x2f20 fs/jfs/jfs_xtree.c
jfs_free_zero_link+0x35b/0x4c0 fs/jfs/namei.c:759
jfs_evict_inode+0x363/0x440 fs/jfs/inode.c:159
evict+0x61e/0xb10 fs/inode.c:837
...
The xtree root of a regular file is embedded in the inode, and
xt_getpage() returns it for bn == 0 with a pseudo metapage. Callers
such as xtTruncate() and xtTruncate_pmap() then decide whether they
hold the root by testing the on-disk p->header.flag & BT_ROOT. In the
reproducer's image a regular file has an xtroot flag of 0 instead of
DXD_INDEX | BT_ROOT | BT_LEAF, so xtTruncate() takes the non-root path
for the embedded root and releases the pseudo metapage as if it were
a real page, dereferencing an invalid folio.
xt_getpage() already validates nextindex and maxentry for both the
root and regular pages. Also reject a page whose BT_ROOT flag does not
match where it came from: the root (bn == 0) must have it set and any
other page must not. Healthy trees always satisfy this, since
xtInitRoot() sets BT_ROOT and xtSplitRoot()/xtSplitPage() never copy it
to a child page.
Tested in a KASAN guest: the syzbot reproducer crashes the unpatched
kernel. With this patch the bad page is reported as
"xt_getpage: xtree page corrupt" and the reproducer runs to completion.
On a clean mkfs.jfs image, writing 40 separate extents to one file
(forcing a root split), remounting, truncating, renaming over an
existing file and remounting again still works, with the data
unchanged.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+43706fd1eb4c8dccdfe6@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=43706fd1eb4c8dccdfe6
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Nicholas Velten <nicholasfvelten@gmail.com>
---
syzbot sent an AI-generated RFC for this bug in May
(https://lore.kernel.org/all/938f325a-46c6-4ade-8a21-b3271963810c@mail.kernel.org/),
which also bundled unrelated txnmgr/logmgr changes and got no replies.
This patch only addresses the xtree root confusion, by validating the
flag in xt_getpage() next to the existing nextindex/maxentry checks.
The reproducer is syzbot's C repro, run in a virtme-ng KASAN guest built
from next-20261009.
Not tested: architectures other than x86_64, and jfs_fsck on the
rejected image.
---
fs/jfs/jfs_xtree.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index 28c3cf960..3a5f9d035 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -121,7 +121,8 @@ static inline xtpage_t *xt_getpage(struct inode *ip, s64 bn, struct metapage **m
(le16_to_cpu(p->header.nextindex) >
le16_to_cpu(p->header.maxentry)) ||
(le16_to_cpu(p->header.maxentry) >
- ((bn == 0) ? XTROOTMAXSLOT : PSIZE >> L2XTSLOTSIZE))) {
+ ((bn == 0) ? XTROOTMAXSLOT : PSIZE >> L2XTSLOTSIZE)) ||
+ ((bn == 0) != !!(p->header.flag & BT_ROOT))) {
jfs_error(ip->i_sb, "xt_getpage: xtree page corrupt\n");
BT_PUTPAGE(*mp);
*mp = NULL;
---
base-commit: becb95e45ef0dda9ffb35156d909d3da7a2789c3
change-id: 20261020-jfs-xtroot-check-e2c2159498b0
Best regards,
--
Nicholas Velten <nicholasfvelten@gmail.com>
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-20 16:32 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20 16:32 [PATCH] jfs: reject xtree pages whose BT_ROOT flag does not match Nicholas Velten via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®