From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from canpmsgout10.his.huawei.com (canpmsgout10.his.huawei.com [113.46.200.225]) (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 E17D41F1513 for ; Thu, 26 Mar 2026 02:15:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.225 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774491328; cv=none; b=DCCnGyUNwwhV3T3h6vvx7aLehVpEVYeGD3ZN2FktpsSXfUYxEdxglDcXzijgMZJMlcSnxBtw/3tFdoOchQqfH579CloBreagxucjxFHW3OdpmphRmLT8XU1ML+vrGuJgZEGPgsjsEFZyJc0a7ygYWsLClJtHfEiYOmJFy9uPEAA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774491328; c=relaxed/simple; bh=cA60xcH0TEe3j8KdRH7/R8590xqJGFkPZF0Te/U3Pck=; h=Subject:To:CC:References:From:Message-ID:Date:MIME-Version: In-Reply-To:Content-Type; b=P6s1/liGhSeZmcAqnJx20j0RjpUvW6m3IDms6Cw4QLPQuOPlxZ8X9o7jNpuJznUbs7QNAdxqLf/N72YUF4SGB6Lfj771UvZwb0uqcve97q6nVRG9dVgHaZ5GbCDS+72l9PL+UdZRy80XDbrznzkKld+WYZd8RtBYBOlmjich96c= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=bplVZWYm; arc=none smtp.client-ip=113.46.200.225 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="bplVZWYm" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=DQF759uthOuQHwEtSunjbV8AhiwRjfvtFsTi97aGrzk=; b=bplVZWYmNUdpoDiE/Re8bpQI9g+K2EI8eD+cX/XJqjVltgrgKDMQ/ZtrUPS3n7wUXpIB7hfB/ T/SLTlEY9rGrl9BU6LyYNhdP0AO4HOzGr0RftBN11l811y9eggZDDs4h4m8atZSqoHuxZITIgbR Nk+H+WkgBqH3cgHReC9WimQ= Received: from mail.maildlp.com (unknown [172.19.163.163]) by canpmsgout10.his.huawei.com (SkyGuard) with ESMTPS id 4fh6f63cKFz1K9f7; Thu, 26 Mar 2026 10:09:18 +0800 (CST) Received: from kwepemk500005.china.huawei.com (unknown [7.202.194.90]) by mail.maildlp.com (Postfix) with ESMTPS id 3AB714048B; Thu, 26 Mar 2026 10:15:22 +0800 (CST) Received: from [10.174.178.46] (10.174.178.46) by kwepemk500005.china.huawei.com (7.202.194.90) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Thu, 26 Mar 2026 10:15:21 +0800 Subject: Re: [PATCH] jffs2: fix use-after-free in jffs2_garbage_collect_thread() To: Dmitriy Chumachenko , David Woodhouse CC: Richard Weinberger , Thomas Gleixner , , , References: <20260323092142.15241-1-Dmitry.Chumachenko@cyberprotect.ru> From: Zhihao Cheng Message-ID: <2fefd248-3afd-c346-7de0-51ce9928d61d@huawei.com> Date: Thu, 26 Mar 2026 10:15:20 +0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In-Reply-To: <20260323092142.15241-1-Dmitry.Chumachenko@cyberprotect.ru> Content-Type: text/plain; charset="gbk"; format=flowed Content-Transfer-Encoding: 8bit X-ClientProxiedBy: kwepems200001.china.huawei.com (7.221.188.67) To kwepemk500005.china.huawei.com (7.202.194.90) ÔÚ 2026/3/23 17:21, Dmitriy Chumachenko дµÀ: > During fuzz testing, the following issue was discovered. > > BUG: KASAN: use-after-free in __lock_acquire+0x3f22/0x53c0 kernel/locking/lockdep.c:4825 > Read of size 8 at addr ffff888053cfa098 by task jffs2_gcd_mtd0/11093 > > CPU: 1 PID: 11093 Comm: jffs2_gcd_mtd0 Not tainted 5.10.232-syzkaller #0 > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 > Call Trace: > __dump_stack lib/dump_stack.c:77 [inline] > dump_stack+0x107/0x167 lib/dump_stack.c:118 > print_address_description.constprop.0+0x1c/0x220 mm/kasan/report.c:377 > __kasan_report mm/kasan/report.c:537 [inline] > kasan_report.cold+0x1f/0x37 mm/kasan/report.c:554 > __lock_acquire+0x3f22/0x53c0 kernel/locking/lockdep.c:4825 > lock_acquire kernel/locking/lockdep.c:5566 [inline] > lock_acquire+0x197/0x480 kernel/locking/lockdep.c:5531 > __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline] > _raw_spin_lock_irqsave+0x36/0x60 kernel/locking/spinlock.c:159 > complete+0x13/0x60 kernel/sched/completion.c:32 > complete_and_exit+0x20/0x40 kernel/exit.c:943 > jffs2_garbage_collect_thread+0x554/0x750 fs/jffs2/background.c:164 > kthread+0x3a9/0x490 kernel/kthread.c:328 > ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:298 > > Allocated by task 11091: > kasan_save_stack+0x1b/0x40 mm/kasan/common.c:48 > kasan_set_track mm/kasan/common.c:56 [inline] > __kasan_kmalloc.constprop.0+0xc9/0xd0 mm/kasan/common.c:461 > kmalloc include/linux/slab.h:552 [inline] > kzalloc include/linux/slab.h:664 [inline] > jffs2_init_fs_context+0x41/0xd0 fs/jffs2/super.c:314 > alloc_fs_context+0x4f9/0x840 fs/fs_context.c:267 > do_new_mount fs/namespace.c:2896 [inline] > path_mount+0xb99/0x2140 fs/namespace.c:3247 > do_mount fs/namespace.c:3260 [inline] > __do_sys_mount fs/namespace.c:3468 [inline] > __se_sys_mount fs/namespace.c:3445 [inline] > __x64_sys_mount+0x283/0x300 fs/namespace.c:3445 > do_syscall_64+0x30/0x40 arch/x86/entry/common.c:46 > entry_SYSCALL_64_after_hwframe+0x67/0xd1 > > Freed by task 28546: > kasan_save_stack+0x1b/0x40 mm/kasan/common.c:48 > kasan_set_track+0x1c/0x30 mm/kasan/common.c:56 > kasan_set_free_info+0x1b/0x30 mm/kasan/generic.c:355 > __kasan_slab_free+0x112/0x170 mm/kasan/common.c:422 > slab_free_hook mm/slub.c:1542 [inline] > slab_free_freelist_hook+0xb8/0x1b0 mm/slub.c:1576 > slab_free mm/slub.c:3149 [inline] > kfree+0xd9/0x360 mm/slub.c:4125 > deactivate_locked_super+0x96/0x170 fs/super.c:335 > deactivate_super+0xb2/0xd0 fs/super.c:366 > cleanup_mnt+0x3a3/0x530 fs/namespace.c:1118 > task_work_run+0xdf/0x1a0 kernel/task_work.c:185 > tracehook_notify_resume include/linux/tracehook.h:188 [inline] > exit_to_user_mode_loop kernel/entry/common.c:172 [inline] > exit_to_user_mode_prepare+0x1de/0x1f0 kernel/entry/common.c:199 > syscall_exit_to_user_mode+0x38/0x1e0 kernel/entry/common.c:274 > > In jffs2_garbage_collect_thread() gc_task is set to NULL and then > kthread_complete_and_exit() calls complete() on gc_thread_exit. These operations > are not atomic: stop path can see gc_task == NULL, skip wait_for_completion(), > and the caller frees jffs2_sb_info while the GC thread still accesses > gc_thread_exit in complete(). > > Fix moving complete() under erase_completion_lock together with gc_task = > NULL, and replacing kthread_complete_and_exit() with kthread_exit(). The > conditional wait in stop path is preserved as it is needed when > jffs2_do_fill_super() fails before start(). > > Found by Linux Verification Center (linuxtesting.org) with Syzkaller. I guess the race window is small and it won't happen in normal mode, the jffs2_garbage_collect_thread is killed by jffs2_stop_garbage_collect_thread normally. For above case, the jffs2_garbage_collect_thread is stopped by other reasons(eg. jffs2_garbage_collect_pass returns ENOSPC, or user sends SIGKILL to jffs2_garbage_collect_thread task). > > Fixes: e2d48b1a98bb ("[JFFS2] Fix cleanup in case of GC-Task not started") > Signed-off-by: Dmitriy Chumachenko > --- > fs/jffs2/background.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c > index bb0ee1a59e71..abf0572dfd3c 100644 > --- a/fs/jffs2/background.c > +++ b/fs/jffs2/background.c > @@ -160,6 +160,7 @@ static int jffs2_garbage_collect_thread(void *_c) > die: > spin_lock(&c->erase_completion_lock); > c->gc_task = NULL; > + complete(&c->gc_thread_exit); > spin_unlock(&c->erase_completion_lock); > - kthread_complete_and_exit(&c->gc_thread_exit, 0); > + kthread_exit(0); > } > Hi, I think the UAF could still happen even this patch is applied. jffs2_kill_sb jffs2_garbage_collect_thread jffs2_stop_garbage_collect_thread spin_lock(&c->erase_completion_lock) send_sig(SIGKILL, c->gc_task, 1) wait = 1 spin_unlock(&c->erase_completion_lock) goto die // receive kill SIGKILL spin_lock(&c->erase_completion_lock) complete(&c->gc_thread_exit) wait_for_completion(&c->gc_thread_exit) // don't wait kfree(c) spin_unlock(&c->erase_completion_lock)