From nobody Wed Apr 8 02:48:25 2026 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.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 797D32620E5 for ; Wed, 11 Mar 2026 02:40:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773196847; cv=none; b=BLAONph8tgeNBnWgUvpz/CQkFe7fIJPZsEfFiBeeuZarhPbqMDK3aKFf+lnhUuPhW2YmEraNyQJdrceybUzYcKJsHULiEeiZGvcgor8nBE4EeWF2Ozi8U61YbWzdzvREIvYaWvALj7Q+VwIRk70phf+aR65/NaircxYEYEfziX8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773196847; c=relaxed/simple; bh=z+0PewQrwdzMhA1aNGeWBKfqEmgGI7QZJtQ7qtbZ1lw=; h=Date:From:To:Subject:Content-Type:MIME-Version:Message-ID; b=c8VFYvJVSxD0S787CfqcsaDqA9LFktoMuVsPIyJzEjLGba6XPdYXbp7JbZID2hZlOgPk2RBgQYxvM9riv7b59ttvu4N37Im7xo+bAuRbUecST9JUUBU8ZFXL/a5crrhudtylHh466WtWIM+tYIr8y5y1z7ACE6D1o1aQhb6VfyY= 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=CaBF/llu; arc=none smtp.client-ip=220.197.31.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="CaBF/llu" 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=z+0PewQrwdzMhA1aNGeWBKfqEmgGI7QZJtQ7qtbZ1lw=; b=C aBF/lluofPrIruJFFka7Zgnj1lFNX6dBfDiGCPo9Y26ADbWm94/BnmrdXSW6+XzR HUSnvF72tXmIjT3/rffCdk9w240OEUWS3IoDXs2Kpq5B6sr4zAujuaZJXj0rIOA2 NjzQONmRSHcQKku2vnQSHZmRw0mbkJ3OZJznYqrKrY= Received: from luckd0g$163.com ( [183.205.138.18] ) by ajax-webmail-wmsvr-40-146 (Coremail) ; Wed, 11 Mar 2026 10:40:03 +0800 (CST) Date: Wed, 11 Mar 2026 10:40:03 +0800 (CST) From: "Jianzhou Zhao" To: linux-kernel@vger.kernel.org, shaggy@kernel.org, liaoyuanhong@vivo.com, jfs-discussion@lists.sourceforge.net Subject: KASAN: slab-use-after-free in lmLogSync 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_Qu2cAf2SuUAr5SecZekfmU4Rhug7UMO3uf8n24JfPJ9wjCzr5C4MZHpGN2Py3OuVMC+gqhiXXAlB7sV7cJNobacNIgpdb44+Rj5W12cY1Wb7CQ== 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: <699cfc53.2878.19cdac3fea8.Coremail.luckd0g@163.com> X-Coremail-Locale: zh_CN X-CM-TRANSID: kigvCgDXP2kD1rBpxdl1AA--.40541W X-CM-SenderInfo: poxfyvkqj6il2tof0z/xtbC9gM8xmmw1gPC5AAA3l X-Coremail-Antispam: 1U5529EdanIXcx71UUUUU7vcSsGvfC2KfnxnUU== Content-Type: text/plain; charset="utf-8" Subject: [BUG] jfs: KASAN: slab-use-after-free in lmLogSync during umount Dear JFS Maintainers, Our fuzzing tool, RacePilot, has detected a slab-use-after-free bug in the = JFS subsystem on a 6.18 kernel version (`6.18.0-08691-g2061f18ad76e-dirty`)= .=20 This issue occurs during [jfs_umount](file:///home/kfuzz/linux/fs/jfs/jfs_u= mount.c#26-119) when handling the `jfs_log` metadata. The [jfs_flush_journa= l](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c#1498-1615) function attempt= s to wait for all outstanding transactions to finish, but fails to account = for transactions that have been handed over to the lazy commit thread ([jfs= _lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#2692-2773)) via t= he `TxAnchor.unlock_queue`. This allows [jfs_umount](file:///home/kfuzz/lin= ux/fs/jfs/jfs_umount.c#26-119) to prematurely free the `jfs_log` object whi= le the [jfs_lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#2692-2= 773) thread is still actively using it. ### Call Trace & Context The bug was triggered with the following trace. (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 lmLogSync+0x7b0/0x7e0 Write of size 4 at addr ffff888054cd4a20 by task jfsCommit/122 CPU: 0 UID: 0 PID: 122 Comm: jfsCommit Tainted: G L 6.18.0= -08691-g2061f18ad76e-dirty #43 PREEMPT(full)=20 Call Trace: lmLogSync+0x7b0/0x7e0 fs/jfs/jfs_logmgr.c:1005 jfs_syncpt+0x8d/0xa0 fs/jfs/jfs_logmgr.c:1041 txEnd+0x30a/0x5a0 fs/jfs/jfs_txnmgr.c:550 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 15338 (umount): ... open_inline_log fs/jfs/jfs_logmgr.c:1159 [inline] lmLogOpen+0x571/0x1420 fs/jfs/jfs_logmgr.c:1069 jfs_mount_rw+0x2f5/0x6d0 fs/jfs/jfs_mount.c:257 ... Freed by task 9847: ... kfree+0x2ca/0x6d0 mm/slub.c:6871 lmLogClose+0x5d0/0x750 fs/jfs/jfs_logmgr.c:1460 jfs_umount+0x2ef/0x440 fs/jfs/jfs_umount.c:114 ... ``` #### Execution Flow & Code Context: **1. The Freeing Path ([jfs_umount](file:///home/kfuzz/linux/fs/jfs/jfs_umo= unt.c#26-119) -> [lmLogClose](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c#= 1422-1496))** During unmount, [jfs_umount](file:///home/kfuzz/linux/fs/jfs/jfs_umount.c#2= 6-119) ([fs/jfs/jfs_umount.c](file:///home/kfuzz/linux/fs/jfs/jfs_umount.c)= ) flushes the journal and then closes/frees the log object: ```c 37: int jfs_umount(struct super_block *sb) 38: { ... 54: if ((log =3D sbi->log)) 55: /* 56: * Wait for outstanding transactions to be written to log: 57: */ 58: jfs_flush_journal(log, 2); ... 106: if (log) { /* log =3D NULL if read-only mount */ 107: updateSuper(sb, FM_CLEAN); 108: /* 109: * close log: 110: * remove file system from log active file system list. 111: */ 112: rc =3D lmLogClose(sb); 113: } ``` The issue stems from [jfs_flush_journal](file:///home/kfuzz/linux/fs/jfs/jf= s_logmgr.c#1498-1615) ([fs/jfs/jfs_txnmgr.c](file:///home/kfuzz/linux/fs/jf= s/jfs_txnmgr.c)), which prematurely returns if `log->cqueue` and `log->sync= list` are empty, ignoring any transactions that have been handed off to the= lazy commit thread (`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](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c#14= 98-1615) returns early, [lmLogClose](file:///home/kfuzz/linux/fs/jfs/jfs_lo= gmgr.c#1422-1496) ([fs/jfs/jfs_logmgr.c](file:///home/kfuzz/linux/fs/jfs/jf= s_logmgr.c)) is called and frees the [log](file:///home/kfuzz/linux/fs/jfs/= jfs_logmgr.c#1187-1220) structure via `kfree(log)`: ```c 1423: /* 1424: * NAME: lmLogClose() ... 1455: if (test_bit(log_INLINELOG, &log->flag)) { 1456: /* 1457: * in-line log in host file system 1458: */ 1459: rc =3D lmLogShutdown(log); 1460: kfree(log); // <--- FREE 1461: goto out; 1462: } ... 1486: rc =3D lmLogShutdown(log); 1488: bdev_fput(bdev_file); 1489:=20 1490: kfree(log); // <--- FREE ``` **2. The Access Path ([jfs_lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_= txnmgr.c#2692-2773) -> [txEnd](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c= #484-571))** Concurrently, a background [jfs_lazycommit](file:///home/kfuzz/linux/fs/jfs= /jfs_txnmgr.c#2692-2773) thread ([fs/jfs/jfs_txnmgr.c](file:///home/kfuzz/l= inux/fs/jfs/jfs_txnmgr.c)) is still processing transactions from `TxAnchor.= unlock_queue`: ```c 2699: int jfs_lazycommit(void *arg) 2700: { ... 2710: while (!list_empty(&TxAnchor.unlock_queue)) { 2711: WorkDone =3D 0; 2712: list_for_each_entry(tblk, &TxAnchor.unlock_queue, 2713: cqueue) { ... 2729: /* Remove transaction from queue */ 2730: list_del(&tblk->cqueue); 2731:=20 2732: LAZY_UNLOCK(flags); 2733: txLazyCommit(tblk); ``` Once the lazy transaction is finished, [txLazyCommit](file:///home/kfuzz/li= nux/fs/jfs/jfs_txnmgr.c#2643-2691) invokes [txEnd](file:///home/kfuzz/linux= /fs/jfs/jfs_txnmgr.c#484-571): ```c 2651: static void txLazyCommit(struct tblock * tblk) 2652: { ... 2681: if (tblk->flag & tblkGC_LAZY) { 2682: spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK 2683: txUnlock(tblk); 2684: tblk->flag &=3D ~tblkGC_LAZY; 2685: txEnd(tblk - TxBlock); /* Convert back to tid */ ``` Finally, [txEnd](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#484-571) ([fs= /jfs/jfs_txnmgr.c](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c)) accesses = the freed [log](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c#1187-1220) obj= ect's members (`log->active` and `log->flag`), resulting in the KASAN Use-A= fter-Free: ```c 493: void txEnd(tid_t tid) 494: { ... 540: /* 541: * mark the tblock not active 542: */ 543: if (--log->active =3D=3D 0) { // <--- UAF access 544: clear_bit(log_FLUSH, &log->flag); // <--- UAF access 545:=20 546: /* 547: * synchronize with logsync barrier 548: */ 549: if (test_bit(log_SYNCBARRIER, &log->flag)) { // <--- UAF access (= triggers KASAN report) 550: TXN_UNLOCK(); 551:=20 552: /* write dirty metadata & forward log syncpt */ 553: jfs_syncpt(log, 1); ``` ### Root Cause Analysis 1. During unmount, [jfs_umount()](file:///home/kfuzz/linux/fs/jfs/jfs_umoun= t.c#26-119) calls [jfs_flush_journal(log, 2)](file:///home/kfuzz/linux/fs/j= fs/jfs_logmgr.c#1498-1615) to wait for all outstanding transactions to comp= lete. 2. [jfs_flush_journal(log, 2)](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c= #1498-1615) attempts to flush all pending journal entries by polling `log->= cqueue` and `log->synclist`. If both lists are empty, it assumes all transa= ctions have completed and breaks its loop. 3. However, if a lazy transaction was already processed by [lmPostGC()](fil= e:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c#790-903) and handed over to [jfs_= lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#2692-2773) via [tx= LazyUnlock()](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#2774-2792), it i= s removed from `log->cqueue` and is pushed onto the global `TxAnchor.unlock= _queue`.=20 4. Therefore, [jfs_flush_journal()](file:///home/kfuzz/linux/fs/jfs/jfs_log= mgr.c#1498-1615) can find `log->cqueue` empty and prematurely return while = the [jfs_lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#2692-2773= ) thread is still processing the transaction from the `unlock_queue`. 5. After [jfs_flush_journal()](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c= #1498-1615) returns, [jfs_umount()](file:///home/kfuzz/linux/fs/jfs/jfs_umo= unt.c#26-119) invokes [lmLogClose(sb)](file:///home/kfuzz/linux/fs/jfs/jfs_= logmgr.c#1422-1496). This completely frees the `jfs_log` metadata (`kfree(l= og)`). 6. Concurrently, [jfs_lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_txnmg= r.c#2692-2773) finishes the lazy transaction and calls [txEnd()](file:///ho= me/kfuzz/linux/fs/jfs/jfs_txnmgr.c#484-571), decrementing `log->active` and= accessing `log->flag` to check for a sync barrier, triggering the slab-use= -after-free on the freed [log](file:///home/kfuzz/linux/fs/jfs/jfs_logmgr.c= #1187-1220) object. ### Potential Impact The impact of this issue is likely limited to a local Denial of Service (ke= rnel crash due to memory corruption/splat) if [jfs_umount](file:///home/kfu= zz/linux/fs/jfs/jfs_umount.c#26-119) is run simultaneously with heavy lazy = transaction loads. While a Use-After-Free condition technically opens the d= oor to arbitrary code execution, this specific scenario executes highly clo= se to unmount time with standard filesystem APIs, reducing exploitability. = The primary concern is stability when lazily committing heavily while a fil= esystem is unmounted. I estimate the hazard strictly as a limited severity = local crash risk. ### Proposed Fix We can fix this issue by having [jfs_flush_journal(log, wait)](file:///home= /kfuzz/linux/fs/jfs/jfs_logmgr.c#1498-1615) also ensure that there are no a= ctive transactions by checking `log->active`. `log->active` correctly track= s the number of active transactions on this specific log, including those m= anaged by [jfs_lazycommit](file:///home/kfuzz/linux/fs/jfs/jfs_txnmgr.c#269= 2-2773). Here is a proposed patch: ```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