Skip to content

Commit cad83c9

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix to avoid racing on fsync_entry_slab by multi filesystem instances
As syzbot reported, there is an use-after-free issue during f2fs recovery: Use-after-free write at 0xffff88823bc16040 (in kfence-#10): kmem_cache_destroy+0x1f/0x120 mm/slab_common.c:486 f2fs_recover_fsync_data+0x75b0/0x8380 fs/f2fs/recovery.c:869 f2fs_fill_super+0x9393/0xa420 fs/f2fs/super.c:3945 mount_bdev+0x26c/0x3a0 fs/super.c:1367 legacy_get_tree+0xea/0x180 fs/fs_context.c:592 vfs_get_tree+0x86/0x270 fs/super.c:1497 do_new_mount fs/namespace.c:2905 [inline] path_mount+0x196f/0x2be0 fs/namespace.c:3235 do_mount fs/namespace.c:3248 [inline] __do_sys_mount fs/namespace.c:3456 [inline] __se_sys_mount+0x2f9/0x3b0 fs/namespace.c:3433 do_syscall_64+0x3f/0xb0 arch/x86/entry/common.c:47 entry_SYSCALL_64_after_hwframe+0x44/0xae The root cause is multi f2fs filesystem instances can race on accessing global fsync_entry_slab pointer, result in use-after-free issue of slab cache, fixes to init/destroy this slab cache only once during module init/destroy procedure to avoid this issue. Reported-by: [email protected] Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent b763f3b commit cad83c9

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

fs/f2fs/f2fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3620,6 +3620,8 @@ void f2fs_destroy_garbage_collection_cache(void);
36203620
*/
36213621
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
36223622
bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi);
3623+
int __init f2fs_create_recovery_cache(void);
3624+
void f2fs_destroy_recovery_cache(void);
36233625

36243626
/*
36253627
* debug.c

fs/f2fs/recovery.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -788,13 +788,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
788788
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
789789
#endif
790790

791-
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
792-
sizeof(struct fsync_inode_entry));
793-
if (!fsync_entry_slab) {
794-
err = -ENOMEM;
795-
goto out;
796-
}
797-
798791
INIT_LIST_HEAD(&inode_list);
799792
INIT_LIST_HEAD(&tmp_inode_list);
800793
INIT_LIST_HEAD(&dir_list);
@@ -867,8 +860,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
867860
}
868861
}
869862

870-
kmem_cache_destroy(fsync_entry_slab);
871-
out:
872863
#ifdef CONFIG_QUOTA
873864
/* Turn quotas off */
874865
if (quota_enabled)
@@ -878,3 +869,17 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
878869

879870
return ret ? ret : err;
880871
}
872+
873+
int __init f2fs_create_recovery_cache(void)
874+
{
875+
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
876+
sizeof(struct fsync_inode_entry));
877+
if (!fsync_entry_slab)
878+
return -ENOMEM;
879+
return 0;
880+
}
881+
882+
void f2fs_destroy_recovery_cache(void)
883+
{
884+
kmem_cache_destroy(fsync_entry_slab);
885+
}

fs/f2fs/super.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4227,9 +4227,12 @@ static int __init init_f2fs_fs(void)
42274227
err = f2fs_create_checkpoint_caches();
42284228
if (err)
42294229
goto free_segment_manager_caches;
4230-
err = f2fs_create_extent_cache();
4230+
err = f2fs_create_recovery_cache();
42314231
if (err)
42324232
goto free_checkpoint_caches;
4233+
err = f2fs_create_extent_cache();
4234+
if (err)
4235+
goto free_recovery_cache;
42334236
err = f2fs_create_garbage_collection_cache();
42344237
if (err)
42354238
goto free_extent_cache;
@@ -4278,6 +4281,8 @@ static int __init init_f2fs_fs(void)
42784281
f2fs_destroy_garbage_collection_cache();
42794282
free_extent_cache:
42804283
f2fs_destroy_extent_cache();
4284+
free_recovery_cache:
4285+
f2fs_destroy_recovery_cache();
42814286
free_checkpoint_caches:
42824287
f2fs_destroy_checkpoint_caches();
42834288
free_segment_manager_caches:
@@ -4303,6 +4308,7 @@ static void __exit exit_f2fs_fs(void)
43034308
f2fs_exit_sysfs();
43044309
f2fs_destroy_garbage_collection_cache();
43054310
f2fs_destroy_extent_cache();
4311+
f2fs_destroy_recovery_cache();
43064312
f2fs_destroy_checkpoint_caches();
43074313
f2fs_destroy_segment_manager_caches();
43084314
f2fs_destroy_node_manager_caches();

0 commit comments

Comments
 (0)