mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jenny Guanni Qu <qguanni@gmail.com>
To: shaggy@kernel.org
Cc: jfs-discussion@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org,
	Jenny Guanni Qu <qguanni@gmail.com>,
	syzbot+a98891ce2318fe7baf05@syzkaller.appspotmail.com
Subject: [PATCH] jfs: fix use-after-free in jfs_readdir on legacy non-indexed directories
Date: Sat, 13 Jun 2026 04:12:04 +0900	[thread overview]
Message-ID: <20260612191204.95876-1-qguanni@gmail.com> (raw)

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)


                 reply	other threads:[~2026-06-12 19:12 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260612191204.95876-1-qguanni@gmail.com \
    --to=qguanni@gmail.com \
    --cc=jfs-discussion@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=shaggy@kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=syzbot+a98891ce2318fe7baf05@syzkaller.appspotmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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