From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 42F0D8462 for ; Fri, 26 Dec 2025 02:58:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766717900; cv=none; b=rN1MYk3NXVNsqrf3EDk4bhqMGbMy+7eCkqbMQ7iy/DbvlYiW3zQtfMrCogg0+rLGhpIZT3SqxIXNJXbBhWma5xqkn235qetWMOcB8ait3+H+OZYLborBZ1086Iy3tOsUfkl7k9SD7t1+1yUA6dAsevTvHqrQ50A7/2P+BbAhvgU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766717900; c=relaxed/simple; bh=YoOPTP2+VJOFRi12WUyWoBQXyY8PiWl4NSEHhwN4mvE=; h=Message-ID:Date:MIME-Version:Cc:Subject:To:References:From: In-Reply-To:Content-Type; b=OV/2VulxrRmKORiboZ/yl/+fgMf8sAuEq83QAbj0wXBldVfiPhp60QmPkd9ZD/8rGe86YHfVR8P0K6nmi/L62VO5qESJlBZJKCExpamiw8WGWJlw+R+tk0OmV5zQNCfCCWHAYhDibRIG6doKYKpOGvXRTE2OtSYEDP6W9UgDVso= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=j3KD55IR; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="j3KD55IR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8B40FC4CEF1; Fri, 26 Dec 2025 02:58:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1766717899; bh=YoOPTP2+VJOFRi12WUyWoBQXyY8PiWl4NSEHhwN4mvE=; h=Date:Cc:Subject:To:References:From:In-Reply-To:From; b=j3KD55IRa/5O6qwzJX41kklpZhthFso7nSwhoM8Va2P5c6vz/hGp1IAidrGSoW6lI PdoBNZ56Ypb5SPybuc5lgviluFcZe3ufWk2Y40v+WUqy/2UENSsHuadJP+2la6gUUp gBJVqj1vOGTdj4j3YEGpCEcqRoSowQeaojYwsXy8h1hht7NhvX35wRw8ahHf7Q7/cQ qvqO7+CA0xVj4jdgw1XL69MvKXd58XyE3QODAHgFmbo3nUwqdZrE6nIZTsiQX8VqVV ks7DSg3aItWslW9U2z1fGgSoFgrjC+CD55NPHTr+s8uKZwA318BQfuZBgPezy4Mgn+ fgKO6dyYS6eww== Message-ID: <83a7a539-e7b5-4ff5-b3d9-c1e9320bf090@kernel.org> Date: Fri, 26 Dec 2025 10:58:23 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Cc: chao@kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, syzbot+b4444e3c972a7a124187@syzkaller.appspotmail.com Subject: Re: [PATCH] f2fs: fix use-after-free in f2fs_write_end_io To: Szymon Wilczek , jaegeuk@kernel.org References: <20251223162823.23606-1-swilczek.lx@gmail.com> Content-Language: en-US From: Chao Yu In-Reply-To: <20251223162823.23606-1-swilczek.lx@gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 12/24/2025 12:28 AM, Szymon Wilczek wrote: > Syzbot reported a slab-use-after-free issue in f2fs_write_end_io(): > [ 86.643336] BUG: KASAN: slab-use-after-free in f2fs_write_end_io+0x9b9/0xb60 > [ 86.644120] Read of size 4 at addr ffff88804357d170 by task kworker/u4:4/45 > ... > [ 86.656543] Call Trace: > ... > [ 86.660351] f2fs_write_end_io+0x9b9/0xb60 > ... > [ 86.685123] Allocated by task 5484: > ... > [ 86.688325] f2fs_fill_super+0x8c/0x6ec0 > ... > [ 86.697685] Freed by task 5484: > ... > [ 86.702700] kfree+0x1c0/0x660 > [ 86.703273] kill_f2fs_super+0x5b6/0x6c0 > > The problem is a race condition between the shutdown of the filesystem > (kill_f2fs_super) and the asynchronous I/O completion handler > (f2fs_write_end_io). > > When unmounting, kill_f2fs_super() frees the sbi structure. However, > if there are pending checkpoint data (CP_DATA) writes, the > f2fs_write_end_io() callback might still be running. > > In the original code, f2fs_write_end_io() accesses sbi->cp_wait after > decrementing the page count. If the page count drops to zero, > f2fs_wait_on_all_pages() in the unmount path returns, allowing > kill_f2fs_super() to free sbi. If the callback then tries to wake up > waiters on sbi->cp_wait, a UAF occurs. > > To fix this, I applied a two-step solution: > > 1. In kill_f2fs_super(), explicitly wait for all CP_DATA pages > to obtain a count of zero using f2fs_wait_on_all_pages(). This > ensures specific synchronization for these metadata writes. > > 2. In f2fs_write_end_io(), move the wake_up() call INSIDE the > bio_for_each_folio_all() loop. This ensures that the wakeup > (which signals completion to the waiter) happens before > processing of the bio is effectively 'done' from the perspective > of the waiter. More importantly, it removes any access to 'sbi' > after the loop, eliminating the UAF window. > > Reported-by: syzbot+b4444e3c972a7a124187@syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?extid=b4444e3c972a7a124187 > Signed-off-by: Szymon Wilczek > --- > fs/f2fs/data.c | 11 ++++++++--- > fs/f2fs/super.c | 1 + > 2 files changed, 9 insertions(+), 3 deletions(-) > > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c > index c30e69392a62..5808d73c2598 100644 > --- a/fs/f2fs/data.c > +++ b/fs/f2fs/data.c > @@ -318,10 +318,13 @@ static void f2fs_write_end_io(struct bio *bio) > { > struct f2fs_sb_info *sbi; > struct folio_iter fi; > + bool is_close; > > iostat_update_and_unbind_ctx(bio); > sbi = bio->bi_private; > > + is_close = is_sbi_flag_set(sbi, SBI_IS_CLOSE); Seems this check may race w/ set_sbi_flag(sbi, SBI_IS_CLOSE). > + > if (time_to_inject(sbi, FAULT_WRITE_IO)) > bio->bi_status = BLK_STS_IOERR; > > @@ -360,10 +363,12 @@ static void f2fs_write_end_io(struct bio *bio) > f2fs_del_fsync_node_entry(sbi, folio); > folio_clear_f2fs_gcing(folio); > folio_end_writeback(folio); > - } > - if (!get_pages(sbi, F2FS_WB_CP_DATA) && > + > + if (!is_close && type == F2FS_WB_CP_DATA && > + !get_pages(sbi, F2FS_WB_CP_DATA) && If F2FS_WB_CP_DATA count is zero, then sbi may be released in kill_f2fs_super(), we should not allow to access sbi->cp_wait below, right? Thanks, > wq_has_sleeper(&sbi->cp_wait)) > - wake_up(&sbi->cp_wait); > + wake_up(&sbi->cp_wait); > + } > > bio_put(bio); > } > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c > index c4c225e09dc4..c9ee3fae1958 100644 > --- a/fs/f2fs/super.c > +++ b/fs/f2fs/super.c > @@ -5454,6 +5454,7 @@ static void kill_f2fs_super(struct super_block *sb) > kill_block_super(sb); > /* Release block devices last, after fscrypt_destroy_keyring(). */ > if (sbi) { > + f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); > destroy_device_list(sbi); > kfree(sbi); > sb->s_fs_info = NULL;