lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251224233133.41078-1-swilczek.lx@gmail.com>
Date: Thu, 25 Dec 2025 00:31:33 +0100
From: Szymon Wilczek <swilczek.lx@...il.com>
To: Dave Kleikamp <shaggy@...nel.org>
Cc: jfs-discussion@...ts.sourceforge.net,
	linux-kernel@...r.kernel.org,
	syzbot+a63afa301d1258d09267@...kaller.appspotmail.com,
	Szymon Wilczek <swilczek.lx@...il.com>
Subject: [PATCH] jfs: add missing tlckBTROOT to txLock calls on inline btree roots

JFS uses "fake" metapages (pointers into the inode's btree root area)
for btree roots that reside inline in the inode. These fake metapages
are identified by the absence of the COMMIT_PAGE flag in xflag.

The txUnlock() and txRelease() functions check for the tlckBTROOT flag
to avoid treating these fake metapages as real disk pages. When txLock()
is called on an inline btree root without tlckBTROOT, txUnlock() later
tries to access mp->nohomeok which doesn't exist in the fake metapage
structure, causing:

  BUG at fs/jfs/jfs_txnmgr.c:932 assert(mp->nohomeok > 0)

This was triggered during directory operations where dtInsert(),
dtDelete(), dtSplitUp(), dtDeleteUp(), xtInsert(), and xtSplitUp()
could operate on inline roots without setting tlckBTROOT.

Fix by adding the tlckBTROOT flag conditionally using BT_IS_ROOT()
check in all txLock() calls that may operate on inline btree roots.
This matches the existing pattern used in dtInitRoot() and
add_missing_indices().

Reported-by: syzbot+a63afa301d1258d09267@...kaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=a63afa301d1258d09267
Signed-off-by: Szymon Wilczek <swilczek.lx@...il.com>
---
 fs/jfs/jfs_dtree.c | 12 ++++++++----
 fs/jfs/jfs_xtree.c |  9 ++++++---
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 0ab83bb7bbdf..c35f4b6f4544 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -881,7 +881,8 @@ int dtInsert(tid_t tid, struct inode *ip,
 	/*
 	 * acquire a transaction lock on the leaf page
 	 */
-	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY |
+		      (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
 	dtlck = (struct dt_lock *) & tlck->lock;
 	ASSERT(dtlck->index == 0);
 	lv = & dtlck->lv[0];
@@ -1258,7 +1259,8 @@ static int dtSplitUp(tid_t tid,
 			/*
 			 * acquire a transaction lock on the parent page
 			 */
-			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY |
+				      (BT_IS_ROOT(smp) ? tlckBTROOT : 0));
 			dtlck = (struct dt_lock *) & tlck->lock;
 			ASSERT(dtlck->index == 0);
 			lv = & dtlck->lv[0];
@@ -2161,7 +2163,8 @@ int dtDelete(tid_t tid,
 		/*
 		 * acquire a transaction lock on the leaf page
 		 */
-		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY |
+		      (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/*
@@ -2383,7 +2386,8 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
 		 *
 		 * action: router entry deletion
 		 */
-		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY |
+			      (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index 28c3cf960c6f..de7d4d5e67a8 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -642,7 +642,8 @@ int xtInsert(tid_t tid,		/* transaction id */
 
 	/* Don't log it if there are no links to the file */
 	if (!test_cflag(COMMIT_Nolink, ip)) {
-		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW |
+			      (BT_IS_ROOT(mp) ? tlckBTROOT : 0));
 		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset =
 		    (xtlck->lwm.offset) ? min(index,
@@ -733,7 +734,8 @@ xtSplitUp(tid_t tid,
 
 		/* Don't log it if there are no links to the file */
 		if (!test_cflag(COMMIT_Nolink, ip)) {
-			tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+			tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW |
+				      tlckBTROOT);
 			xtlck = (struct xtlock *) & tlck->lock;
 			xtlck->lwm.offset = (xtlck->lwm.offset) ?
 			    min(skip, (int)xtlck->lwm.offset) : skip;
@@ -903,7 +905,8 @@ xtSplitUp(tid_t tid,
 			/* Don't log it if there are no links to the file */
 			if (!test_cflag(COMMIT_Nolink, ip)) {
 				tlck = txLock(tid, ip, smp,
-					      tlckXTREE | tlckGROW);
+					      tlckXTREE | tlckGROW |
+					      (BT_IS_ROOT(smp) ? tlckBTROOT : 0));
 				xtlck = (struct xtlock *) & tlck->lock;
 				xtlck->lwm.offset = (xtlck->lwm.offset) ?
 				    min(skip, (int)xtlck->lwm.offset) : skip;
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ