mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] jfs: fix use-after-free in jfs_readdir on legacy non-indexed directories
@ 2026-06-12 19:12 Jenny Guanni Qu
  0 siblings, 0 replies; only message in thread
From: Jenny Guanni Qu @ 2026-06-12 19:12 UTC (permalink / raw)
  To: shaggy
  Cc: jfs-discussion, linux-kernel, stable, Jenny Guanni Qu,
	syzbot+a98891ce2318fe7baf05

In the legacy (non-indexed) readdir path, jfs_readdir calls dtReadNext
to advance through the directory's dtree. When dtReadNext reaches the
last leaf page, it frees the metapage via DT_PUTPAGE(mp), sets bn = -1,
and falls through to the out label, which stores the stale mp pointer
into btstack->top->mp.

Back in jfs_readdir, DT_GETSEARCH dereferences btstack.top->mp to
extract the dtpage pointer. It guards this with "if (BN)", intending to
distinguish root (bn=0) from non-root pages, but the -1 EOF sentinel
also passes this check, causing a read from the freed metapage slab
object.

The existing code already had the correct EOF check ("offset beyond
directory eof?") immediately after DT_GETSEARCH, but the dereference
inside the macro fires first. Fix this by moving the bn < 0 check
before the DT_GETSEARCH call, reading btstack.top->bn directly since
the local bn variable is not yet populated.

Also null out the stale mp pointer in dtReadNext when bn is -1, so the
btstack does not retain a dangling pointer to freed memory.

The buggy ordering predates the git history; the EOF check has followed
DT_GETSEARCH since the initial JFS merge, so there is no specific
commit to reference in a Fixes: tag.

Reported-by: syzbot+a98891ce2318fe7baf05@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a98891ce2318fe7baf05
Cc: stable@vger.kernel.org
Signed-off-by: Jenny Guanni Qu <qguanni@gmail.com>
---
Reproduced the crash on an x86_64 KASAN kernel (v7.1-rc6) using a C
reproducer that mounts a JFS image, clears JFS_DIR_INDEX in the
superblock to force the legacy non-indexed readdir path, and calls
getdents64 past the last leaf page. The faulting access resolves via
faddr2line to the DT_GETSEARCH dereference in jfs_readdir, and the free
to release_metapage in dtReadNext, matching the syzbot report. syzbot's
own published C reproducer produces an identical crash signature on the
same kernel.

With this patch applied (v7.1-rc8), the same reproducer drives the
identical code path (600 entries, repeated getdents64 calls through the
legacy jfs_readdir loop) and completes with no KASAN report.

 fs/jfs/jfs_dtree.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index ac0f79fafaca..037121587571 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -2874,14 +2874,14 @@ int jfs_readdir(struct file *file, struct dir_context *ctx)
 			ctx->pos = DIREND;
 			return 0;
 		}
-		/* get start leaf page and index */
-		DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
-
 		/* offset beyond directory eof ? */
-		if (bn < 0) {
+		if (btstack.top->bn < 0) {
 			ctx->pos = DIREND;
 			return 0;
 		}
+
+		/* get start leaf page and index */
+		DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 	}
 
 	dirent_buf = __get_free_page(GFP_KERNEL);
@@ -3293,7 +3293,7 @@ static int dtReadNext(struct inode *ip, loff_t * offset,
 	btsp = btstack->top;
 	btsp->bn = bn;
 	btsp->index = dtoffset->index;
-	btsp->mp = mp;
+	btsp->mp = (bn == -1) ? NULL : mp;
 
 	return 0;
 }
-- 
2.50.1 (Apple Git-155)


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

only message in thread, other threads:[~2026-06-12 19:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-12 19:12 [PATCH] jfs: fix use-after-free in jfs_readdir on legacy non-indexed directories Jenny Guanni Qu

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

Powered by JetHome