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: syzbot+9d90dad32dd9727ed084@syzkaller.appspotmail.com Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
b763f3bedc
commit
cad83c968c
|
@ -3620,6 +3620,8 @@ void f2fs_destroy_garbage_collection_cache(void);
|
|||
*/
|
||||
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
|
||||
bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_recovery_cache(void);
|
||||
void f2fs_destroy_recovery_cache(void);
|
||||
|
||||
/*
|
||||
* debug.c
|
||||
|
|
|
@ -788,13 +788,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
|||
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
|
||||
#endif
|
||||
|
||||
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
|
||||
sizeof(struct fsync_inode_entry));
|
||||
if (!fsync_entry_slab) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&inode_list);
|
||||
INIT_LIST_HEAD(&tmp_inode_list);
|
||||
INIT_LIST_HEAD(&dir_list);
|
||||
|
@ -867,8 +860,6 @@ skip:
|
|||
}
|
||||
}
|
||||
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
out:
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Turn quotas off */
|
||||
if (quota_enabled)
|
||||
|
@ -878,3 +869,17 @@ out:
|
|||
|
||||
return ret ? ret : err;
|
||||
}
|
||||
|
||||
int __init f2fs_create_recovery_cache(void)
|
||||
{
|
||||
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
|
||||
sizeof(struct fsync_inode_entry));
|
||||
if (!fsync_entry_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_destroy_recovery_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
}
|
||||
|
|
|
@ -4227,9 +4227,12 @@ static int __init init_f2fs_fs(void)
|
|||
err = f2fs_create_checkpoint_caches();
|
||||
if (err)
|
||||
goto free_segment_manager_caches;
|
||||
err = f2fs_create_extent_cache();
|
||||
err = f2fs_create_recovery_cache();
|
||||
if (err)
|
||||
goto free_checkpoint_caches;
|
||||
err = f2fs_create_extent_cache();
|
||||
if (err)
|
||||
goto free_recovery_cache;
|
||||
err = f2fs_create_garbage_collection_cache();
|
||||
if (err)
|
||||
goto free_extent_cache;
|
||||
|
@ -4278,6 +4281,8 @@ free_garbage_collection_cache:
|
|||
f2fs_destroy_garbage_collection_cache();
|
||||
free_extent_cache:
|
||||
f2fs_destroy_extent_cache();
|
||||
free_recovery_cache:
|
||||
f2fs_destroy_recovery_cache();
|
||||
free_checkpoint_caches:
|
||||
f2fs_destroy_checkpoint_caches();
|
||||
free_segment_manager_caches:
|
||||
|
@ -4303,6 +4308,7 @@ static void __exit exit_f2fs_fs(void)
|
|||
f2fs_exit_sysfs();
|
||||
f2fs_destroy_garbage_collection_cache();
|
||||
f2fs_destroy_extent_cache();
|
||||
f2fs_destroy_recovery_cache();
|
||||
f2fs_destroy_checkpoint_caches();
|
||||
f2fs_destroy_segment_manager_caches();
|
||||
f2fs_destroy_node_manager_caches();
|
||||
|
|
Loading…
Reference in New Issue