From nobody Wed Apr 8 01:16:36 2026 Received: from m16.mail.163.com (m16.mail.163.com [117.135.210.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 817BA1A9FA0 for ; Wed, 11 Mar 2026 02:57:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=117.135.210.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773197827; cv=none; b=ItuxGrxjc96ZUbCAXgeYduuMQ8tfU0eycVKRHAL4/1A3U8vIQ6PfVqRI+73SYyCnaW+LdX24iIynPkM01LLbLyJ+cLoxBnnPSIbL4Y9zB1oIE05QkoOI0LjH9LHmBOuXMREfoWC7lPcJ3pnJmLObuvvnhbH0qzCYI53TqBtLAUw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773197827; c=relaxed/simple; bh=6XbYUOUr4VIrBdFRw7pR7saFxderEONFAddPtJwG7CI=; h=Date:From:To:Subject:Content-Type:MIME-Version:Message-ID; b=NtKlWnBVtNkYa2V/FOE7xkb1GY2ajjimQg1Y1yXLFzO7NsOzkvY1s0oyEqphEq8gtPQNGFEHBiEw9n43BDddy4dzDt12D1EPTRpSBq0Wt8KiRurhp0t/wMW1/8mM7h6c4d1iFI+ZXmyp8O5zK4K9Fnn4fblI18seu+5ixqz1SFU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=Ukhw5dT9; arc=none smtp.client-ip=117.135.210.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="Ukhw5dT9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=Date:From:To:Subject:Content-Type:MIME-Version: Message-ID; bh=6XbYUOUr4VIrBdFRw7pR7saFxderEONFAddPtJwG7CI=; b=U khw5dT9pRkEbhKHq/kMp86bMfaf0nskGXbBXSpf9ZIPqnlGcd8V2RcGVCU0brtxH ZukEkgET+WjDbogYDox31UozUy11/l2JRkwV1iCSvyaRRV8shLT3vAJkHDiqHd4H W3cVLpWL2u2TAX0FkrGyE4OFdE+PslSDGFs/zn11sc= Received: from luckd0g$163.com ( [183.205.138.18] ) by ajax-webmail-wmsvr-40-146 (Coremail) ; Wed, 11 Mar 2026 10:56:37 +0800 (CST) Date: Wed, 11 Mar 2026 10:56:37 +0800 (CST) From: "Jianzhou Zhao" To: jfs-discussion@lists.sourceforge.net, liaoyuanhong@vivo.com, shaggy@kernel.org, linux-kernel@vger.kernel.org Subject: KASAN: slab-use-after-free in txEnd during umount X-Priority: 3 X-Mailer: Coremail Webmail Server Version 2023.4-cmXT build 20251222(83accb85) Copyright (c) 2002-2026 www.mailtech.cn 163com X-NTES-SC: AL_Qu2cAf2SuE8i4SefYekfmU4Rhug7UMO3uf8n24JfPJ9wjCzr5C4MZHpGN2Py3OuVMC+gqhiXXAlB7sV7cJNobacN8oCkL8IqHJXv9WAcy5W+Ug== Content-Transfer-Encoding: quoted-printable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <11adc2bb.2dc4.19cdad3299e.Coremail.luckd0g@163.com> X-Coremail-Locale: zh_CN X-CM-TRANSID: kigvCgD3P2vm2bBp9uB1AA--.40765W X-CM-SenderInfo: poxfyvkqj6il2tof0z/xtbC9gY2wGmw2eYb4gAA3Z X-Coremail-Antispam: 1U5529EdanIXcx71UUUUU7vcSsGvfC2KfnxnUU== Content-Type: text/plain; charset="utf-8" Subject: [BUG] jfs: KASAN: slab-use-after-free in txEnd during umount (`jfs= _sb_info`) Dear Maintainers, Our fuzzing tool, RacePilot, has detected another slab-use-after-free bug i= n the JFS subsystem on a 6.18 kernel version (`6.18.0-08691-g2061f18ad76e-d= irty`).=20 This issue is closely related to the previously reported UAF in `lmLogSync`= . It shares the same root cause: the `jfs_flush_journal` function failing t= o wait for lazy transactions handled by the `jfs_lazycommit` thread before = allowing the unmount process to continue. In this specific trace, it manife= sts as a Use-After-Free on the `jfs_sb_info` (`sbi`) structure inside `txEn= d()`, rather than on the `jfs_log` structure. ### Call Trace & Context The KASAN splat reveals a read use-after-free on an object constructed by `= jfs_fill_super`. (Note: Due to source-level instrumentation with RacePilot,= the line numbers in the trace correspond to the instrumented source block = provided below). ``` BUG: KASAN: slab-use-after-free in txEnd+0x53e/0x5a0 fs/jfs/jfs_txnmgr.c:507 Read of size 8 at addr ffff88804f850c30 by task jfsCommit/121 CPU: 0 UID: 0 PID: 121 Comm: jfsCommit Tainted: G L 6.18.0= -08691-g2061f18ad76e-dirty #43 PREEMPT(full)=20 Call Trace: txEnd+0x53e/0x5a0 fs/jfs/jfs_txnmgr.c:507 txLazyCommit fs/jfs/jfs_txnmgr.c:2685 [inline] jfs_lazycommit+0x6f0/0xb10 fs/jfs/jfs_txnmgr.c:2734 kthread+0x3d0/0x780 kernel/kthread.c:463 Allocated by task 27991 (mount): ... jfs_fill_super+0xd1/0x1030 fs/jfs/super.c:452 get_tree_bdev_flags+0x389/0x620 fs/super.c:1699 ... Freed by task 9895 (umount): ... kfree+0x2ca/0x6d0 mm/slub.c:6871 generic_shutdown_super+0x156/0x390 fs/super.c:643 kill_block_super+0x3b/0x90 fs/super.c:1730 ... ``` #### Execution Flow & Code Context: **1. The Freeing Path (`generic_shutdown_super` -> `jfs_put_super`)** During unmount, `jfs_umount` flushes the journal via `jfs_flush_journal(log= , 2)`. However, `jfs_flush_journal` (`fs/jfs/jfs_txnmgr.c`) prematurely ret= urns if `log->cqueue` and `log->synclist` are empty. It fails to check if t= here are remaining transactions in the lazy commit queue (`TxAnchor.unlock_= queue`): ```c 1498: /* 1499: * NAME: jfs_flush_journal() ... 1577: if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) { ... 1581: if (list_empty(&log->cqueue) && 1582: list_empty(&log->synclist)) 1583: break; // <--- Premature return ``` Because `jfs_flush_journal` returns early, the unmount process resumes and = eventually invokes `generic_shutdown_super`, calling the filesystem's `put_= super` callback (`jfs_put_super` in `fs/jfs/super.c`). This gracefully free= s the `jfs_sb_info` memory allocation (`kfree(sbi)`): ```c 190: static void jfs_put_super(struct super_block *sb) 191: { ... 194: kfree(sbi); // <--- sbi is freed here 195: } ``` **2. The Access Path (`jfs_lazycommit` -> `txEnd`)** Concurrently, a background `jfs_lazycommit` thread (`fs/jfs/jfs_txnmgr.c`) = is still processing transactions pushed to the `TxAnchor.unlock_queue` befo= re unmount: ```c 2699: int jfs_lazycommit(void *arg) 2700: { ... 2710: while (!list_empty(&TxAnchor.unlock_queue)) { ... 2732: LAZY_UNLOCK(flags); 2733: txLazyCommit(tblk); ``` When finishing the lazily executed transaction, `txLazyCommit` invokes `txE= nd()`. ```c 2651: static void txLazyCommit(struct tblock * tblk) 2652: { ... 2684: tblk->flag &=3D ~tblkGC_LAZY; 2685: txEnd(tblk - TxBlock); /* Convert back to tid */ ``` Finally, `txEnd` (`fs/jfs/jfs_txnmgr.c`) attempts to fetch the `log` object= pointer by dereferencing the private `sb->s_fs_info` pointer (`sbi`). Sinc= e `sbi` was already freed in `jfs_put_super()`, this triggers the KASAN Use= -After-Free: ```c 493: void txEnd(tid_t tid) 494: { ... 507: log =3D JFS_SBI(tblk->sb)->log; // <--- UAF access to freed sbi block ``` ### Root Cause Analysis This bug shares the exact identical root cause with the previously reported= `lmLogSync` UAF bug. `jfs_flush_journal(log, 2)` fails to properly check `= TxAnchor.unlock_queue` (or active transactions handled by the lazy thread) = before returning during the unmount process. Because of this race condition= , varying timing can lead to `jfs_lazycommit` either dereferencing the free= d `sbi` (when `txEnd` starts execution) or the freed `log` metadata (subseq= uently in `txEnd`). Regrettably, we were unable to create a reproduction pr= ogram for this bug. ### Potential Impact Similar to the previous report, the primary hazard boils down to a local De= nial of Service (memory corruption/splat) if lazy transactions coincide int= ensely with filesystem unmounting operations. We gauge the exploitability r= isk to be low, as standard interactions around the filesystem lifecycle unm= ount mechanism heavily restrain the scope to trigger arbitrary execution, r= esulting in predominantly a local crash risk. ### Proposed Fix Just as before, resolving the early return of `jfs_flush_journal` effective= ly resolves this UAF as well, since it correctly blocks the umount sequence= until the `jfs_lazycommit` thread has finished processing on both `log` an= d `sbi`.=20 We can evaluate `log->active` inside `jfs_flush_journal` to fully capture a= ny transactions handled by `jfs_lazycommit` before permitting the unmount t= o proceed. ```diff --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1574,11 +1574,12 @@ void jfs_flush_journal(struct jfs_log *log, int wai= t) /* * If there was recent activity, we may need to wait * for the lazycommit thread to catch up */ - if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) { + if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist) || + log->active) { for (i =3D 0; i < 200; i++) { /* Too much? */ msleep(250); write_special_inodes(log, filemap_fdatawrite); if (list_empty(&log->cqueue) && - list_empty(&log->synclist)) + list_empty(&log->synclist) && + !log->active) break; } } ``` We would be highly honored if this could be of any help. Best regards, RacePilot Team