summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChao Yu <chao@kernel.org>2026-01-07 14:22:18 +0300
committerJaegeuk Kim <jaegeuk@kernel.org>2026-01-17 03:00:34 +0300
commitce2739e482bce8d2c014d76c4531c877f382aa54 (patch)
treeaee1989f01c637dd8c8b2fd1f726578052ceedae
parent3996b70209f145bfcf2afc7d05dd92c27b233b48 (diff)
downloadlinux-ce2739e482bce8d2c014d76c4531c877f382aa54.tar.xz
f2fs: fix to avoid UAF in f2fs_write_end_io()
As syzbot reported an use-after-free issue in f2fs_write_end_io(). It is caused by below race condition: loop device umount - worker_thread - loop_process_work - do_req_filebacked - lo_rw_aio - lo_rw_aio_complete - blk_mq_end_request - blk_update_request - f2fs_write_end_io - dec_page_count - folio_end_writeback - kill_f2fs_super - kill_block_super - f2fs_put_super : free(sbi) : get_pages(, F2FS_WB_CP_DATA) accessed sbi which is freed In kill_f2fs_super(), we will drop all page caches of f2fs inodes before call free(sbi), it guarantee that all folios should end its writeback, so it should be safe to access sbi before last folio_end_writeback(). Let's relocate ckpt thread wakeup flow before folio_end_writeback() to resolve this issue. Cc: stable@kernel.org Fixes: e234088758fc ("f2fs: avoid wait if IO end up when do_checkpoint for better performance") Reported-by: syzbot+b4444e3c972a7a124187@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=b4444e3c972a7a124187 Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/data.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 2e133a723b99..f461f1318b4c 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -378,14 +378,20 @@ static void f2fs_write_end_io(struct bio *bio)
folio->index != nid_of_node(folio));
dec_page_count(sbi, type);
+
+ /*
+ * we should access sbi before folio_end_writeback() to
+ * avoid racing w/ kill_f2fs_super()
+ */
+ if (type == F2FS_WB_CP_DATA && !get_pages(sbi, type) &&
+ wq_has_sleeper(&sbi->cp_wait))
+ wake_up(&sbi->cp_wait);
+
if (f2fs_in_warm_node_list(sbi, folio))
f2fs_del_fsync_node_entry(sbi, folio);
folio_clear_f2fs_gcing(folio);
folio_end_writeback(folio);
}
- if (!get_pages(sbi, F2FS_WB_CP_DATA) &&
- wq_has_sleeper(&sbi->cp_wait))
- wake_up(&sbi->cp_wait);
bio_put(bio);
}