From: Al Viro viro@zeniv.linux.org.uk
mainline inclusion from mainline-v6.1-rc1 commit 9d64d2405f7d30d49818f6682acd0392348f0fdb category: bugfix bugzilla: 187857, https://gitee.com/src-openeuler/kernel/issues/I5X9DT CVE: CVE-2022-3577
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
So far we relied on .put_super = binderfs_put_super() to destroy info we stashed in sb->s_fs_info. This gave us the required ordering between ->evict_inode() and sb->s_fs_info destruction.
But the current implementation of binderfs_fill_super() has a memory leak in the rare circumstance that d_make_root() fails because ->put_super() is only called when sb->s_root is initialized. Fix this by removing ->put_super() and simply do all that work in binderfs_kill_super().
Reported-by: Dongliang Mu mudongliangabcd@gmail.com Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Christian Brauner (Microsoft) brauner@kernel.org Link: https://lore.kernel.org/r/20220823095339.853371-1-brauner@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Li Huafei lihuafei1@huawei.com Reviewed-by: Kuohai Xu xukuohai@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/android/binderfs.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 7b4f154f07e6..a3beb685748c 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -330,22 +330,10 @@ static int binderfs_show_options(struct seq_file *seq, struct dentry *root) return 0; }
-static void binderfs_put_super(struct super_block *sb) -{ - struct binderfs_info *info = sb->s_fs_info; - - if (info && info->ipc_ns) - put_ipc_ns(info->ipc_ns); - - kfree(info); - sb->s_fs_info = NULL; -} - static const struct super_operations binderfs_super_ops = { .evict_inode = binderfs_evict_inode, .show_options = binderfs_show_options, .statfs = simple_statfs, - .put_super = binderfs_put_super, };
static inline bool is_binderfs_control_device(const struct dentry *dentry) @@ -763,11 +751,27 @@ static int binderfs_init_fs_context(struct fs_context *fc) return 0; }
+static void binderfs_kill_super(struct super_block *sb) +{ + struct binderfs_info *info = sb->s_fs_info; + + /* + * During inode eviction struct binderfs_info is needed. + * So first wipe the super_block then free struct binderfs_info. + */ + kill_litter_super(sb); + + if (info && info->ipc_ns) + put_ipc_ns(info->ipc_ns); + + kfree(info); +} + static struct file_system_type binder_fs_type = { .name = "binder", .init_fs_context = binderfs_init_fs_context, .parameters = binderfs_fs_parameters, - .kill_sb = kill_litter_super, + .kill_sb = binderfs_kill_super, .fs_flags = FS_USERNS_MOUNT, };