From nobody Mon Sep 28 21:54:18 2026 Received: from mail.amicon.ru (unknown [77.108.111.100]) (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 DF2EC282F34 for ; Mon, 17 Aug 2026 07:13:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=77.108.111.100 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786950842; cv=none; b=M+gQub2tnwnEO84QUftMhfON2Pp4GwoH7N4aYD0UzDJJra+NhTpldXOo9Ulk9qQ+OyOvOLkzhfv3/Mf7X55mwnqR4bMfVmh53xFaEF1oSGxAQO0Nn/+O6Ndi58BCrjryhSrmyFSY4fGYKEqSOdab7lfrZindHDwwgKGD1U0m4ts= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786950842; c=relaxed/simple; bh=11HQSf109QmtYE3Qo9JS9oUyc5AUtSbuZTgIthz2DXM=; h=Content-Type:From:To:CC:Subject:Date:Message-ID:MIME-Version; b=GpJEvb3QrG+PyflGdxqSf6QK0Bu76Cx/uNvGNOwnF2yaQhWT9fzFL5w8nNPFWZuEF/ZGAiM5OEF+kSX/hpsFFHDC/zZHtdyt+/HHq8b0YCSA6X8vPXxx2mTNxrUDPKHkTIyeJHzF42HaLG2bhPfuXo522blM5tsq8q/C/qcTfdY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amicon.ru; spf=pass smtp.mailfrom=amicon.ru; dkim=pass (2048-bit key) header.d=amicon.ru header.i=@amicon.ru header.b=F3mFqlbF; arc=none smtp.client-ip=77.108.111.100 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amicon.ru Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amicon.ru Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=amicon.ru header.i=@amicon.ru header.b="F3mFqlbF" Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; d=amicon.ru; s=mail; c=simple/simple; t=1786950834; h=from:subject:to:date:message-id; bh=11HQSf109QmtYE3Qo9JS9oUyc5AUtSbuZTgIthz2DXM=; b=F3mFqlbFutXrsmQuF7LDtds40ZTWKHxW9VAMXIlCcGZgtQtRCH+edj/mUmfRXIxYwqv6bSfmLjm vyrrFljp033QXTzfFSfcfJd5aDV2X31MIAiaR1hEfQovCfaYxwLVmscl27AKLf2BiUpSPJJDX07Au mfX5dedhREcPOZcvse0Ld0ZKilsdFHtCMZTgbA3N+znLU/g5cLwrm7MhouPbaPa45bqkwUKN7VoGO en6HFAcc3nN45fA0GhHnUHEewkRconZuBj7uc8FPxyJLSUZ15TTfiH73bLulC5+ywJj19x/ZCwTnF zRV93NtVKCGIBm/7cNABgiW9un9eK1Rg9JYA== Received: from localhost.localdomain (192.168.3.117) by mail.amicon.lan (192.168.0.59) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.27; Mon, 17 Aug 2026 10:13:54 +0300 From: Aleksandr Khromov To: Dave Kleikamp CC: , , , , Subject: [PATCH] jfs: fix double free of the log superblock buffer in lmLogInit() Date: Mon, 17 Aug 2026 10:13:47 +0300 Message-ID: <20260817071347.1160598-1-haa@amicon.ru> X-Mailer: git-send-email 2.48.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mail.amicon.lan (192.168.0.59) To mail.amicon.lan (192.168.0.59) Content-Type: text/plain; charset="utf-8" lbmIOWait() called with the lbmFREE flag returns the buffer to the log buffer free list unconditionally, before it reports the outcome of the i/o. lmLogInit() ignores that and, when the write of the log superblock fails, jumps to errout30, which falls through to errout20 and calls lbmFree(bpsuper) a second time. The second lbmFree() inserts the buffer into the singly linked free list twice, which makes the list circular. lbmLogShutdown(), called right after on the same error path, walks that list until it hits NULL, so it never terminates: the mounting task ends up freeing the same lbufs and their pages over and over in an endless loop inside the kernel - a repeated double free, with the usual consequences once the freed memory is handed out to someone else. The write of the log superblock is the very first write to the device after the log is opened, so no fault injection is needed to reach the failure: mounting a crafted image whose s_logpxd points outside the device is enough. KASAN, mounting a crafted image on a loop device (offsets decoded with scripts/decode_stacktrace.sh): metapage_write_end_io: I/O error BUG: KASAN: double-free in lmLogInit (fs/jfs/jfs_logmgr.c:1862 fs/jfs/jfs= _logmgr.c:1413) Free of addr ffff8881027c8a00 by task init/71 CPU: 1 UID: 0 PID: 71 Comm: init Tainted: G B 7.2.0-rc7-g2f1baf1fc892= #2 PREEMPT(lazy) Tainted: [B]=3DBAD_PAGE Hardware name: QEMU Ubuntu 25.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-de= bian-1.16.3-2 04/01/2014 Call Trace: kfree (mm/slub.c:6692) lmLogInit (fs/jfs/jfs_logmgr.c:1862 fs/jfs/jfs_logmgr.c:1413) lmLogOpen (fs/jfs/jfs_logmgr.c:1173 fs/jfs/jfs_logmgr.c:1067) jfs_mount_rw (fs/jfs/jfs_mount.c:257) jfs_fill_super (fs/jfs/super.c:533) get_tree_bdev_flags (fs/super.c:1640) vfs_get_tree (fs/super.c:1700) path_mount (fs/namespace.c:4161) __x64_sys_mount (fs/namespace.c:4367) Freed by task 71: kfree (mm/slub.c:6692) lmLogInit (fs/jfs/jfs_logmgr.c:1862 fs/jfs/jfs_logmgr.c:1413) lmLogOpen (fs/jfs/jfs_logmgr.c:1173 fs/jfs/jfs_logmgr.c:1067) jfs_mount_rw (fs/jfs/jfs_mount.c:257) jfs_logmgr.c:1413 is the errout10 lbmLogShutdown() call and :1862 is its kfree(lbuf) - the shutdown loop walks the free list that the second lbmFree() made circular, so it keeps re-freeing the same lbufs; KASAN also flags the accompanying slab-use-after-free reads of the freed l_freelist on every extra pass. Clear bpsuper once lbmIOWait() has disposed of it and make errout20 skip the release in that case. Found by Linux Verification Center (linuxtesting.org). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Aleksandr Khromov --- fs/jfs/jfs_logmgr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 695415cbfe98..3277701d306d 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1242,7 +1242,7 @@ int lmLogInit(struct jfs_log * log) int rc =3D 0; struct lrd lrd; struct logsuper *logsuper; - struct lbuf *bpsuper; + struct lbuf *bpsuper =3D NULL; struct lbuf *bp; struct logpage *lp; int lsn =3D 0; @@ -1380,7 +1380,13 @@ int lmLogInit(struct jfs_log * log) log->serial =3D le32_to_cpu(logsuper->serial) + 1; logsuper->serial =3D cpu_to_le32(log->serial); lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); - if ((rc =3D lbmIOWait(bpsuper, lbmFREE))) + rc =3D lbmIOWait(bpsuper, lbmFREE); + /* + * lbmIOWait() with lbmFREE has already returned bpsuper + * to the free list, whatever the outcome of the i/o. + */ + bpsuper =3D NULL; + if (rc) goto errout30; } =20 @@ -1410,7 +1416,8 @@ int lmLogInit(struct jfs_log * log) lbmFree(bp); =20 errout20: /* release log superblock */ - lbmFree(bpsuper); + if (bpsuper) + lbmFree(bpsuper); =20 errout10: /* unwind lbmLogInit() */ lbmLogShutdown(log); --=20 2.48.1