btrfs: sanitize security_mnt_opts use

1) keeping a copy in btrfs_fs_info is completely pointless - we never
use it for anything.  Getting rid of that allows for simpler calling
conventions for setup_security_options() (caller is responsible for
freeing mnt_opts in all cases).

2) on remount we want to use ->sb_remount(), not ->sb_set_mnt_opts(),
same as we would if not for FS_BINARY_MOUNTDATA.  Behaviours *are*
close (in fact, selinux sb_set_mnt_opts() ought to punt to
sb_remount() in "already initialized" case), but let's handle
that uniformly.  And the only reason why the original btrfs changes
didn't go for security_sb_remount() in btrfs_remount() case is that
it hadn't been exported.  Let's export it for a while - it'll be
going away soon anyway.

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2018-12-10 17:19:21 -05:00
parent 8d64124a6a
commit a65001e8a4
3 changed files with 10 additions and 58 deletions

View File

@ -1100,9 +1100,6 @@ struct btrfs_fs_info {
struct mutex unused_bg_unpin_mutex; struct mutex unused_bg_unpin_mutex;
struct mutex delete_unused_bgs_mutex; struct mutex delete_unused_bgs_mutex;
/* For btrfs to record security options */
struct security_mnt_opts security_opts;
/* /*
* Chunks that can't be freed yet (under a trim/discard operation) * Chunks that can't be freed yet (under a trim/discard operation)
* and will be latter freed. Protected by fs_info->chunk_mutex. * and will be latter freed. Protected by fs_info->chunk_mutex.
@ -2959,7 +2956,6 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
kfree(fs_info->free_space_root); kfree(fs_info->free_space_root);
kfree(fs_info->super_copy); kfree(fs_info->super_copy);
kfree(fs_info->super_for_commit); kfree(fs_info->super_for_commit);
security_free_mnt_opts(&fs_info->security_opts);
kvfree(fs_info); kvfree(fs_info);
} }

View File

@ -1458,43 +1458,6 @@ out:
return root; return root;
} }
static int parse_security_options(char *orig_opts,
struct security_mnt_opts *sec_opts)
{
return security_sb_eat_lsm_opts(orig_opts, sec_opts);
}
static int setup_security_options(struct btrfs_fs_info *fs_info,
struct super_block *sb,
struct security_mnt_opts *sec_opts)
{
int ret = 0;
/*
* Call security_sb_set_mnt_opts() to check whether new sec_opts
* is valid.
*/
ret = security_sb_set_mnt_opts(sb, sec_opts, 0, NULL);
if (ret)
return ret;
#ifdef CONFIG_SECURITY
if (!fs_info->security_opts.num_mnt_opts) {
/* first time security setup, copy sec_opts to fs_info */
memcpy(&fs_info->security_opts, sec_opts, sizeof(*sec_opts));
} else {
/*
* Since SELinux (the only one supporting security_mnt_opts)
* does NOT support changing context during remount/mount of
* the same sb, this must be the same or part of the same
* security options, just free it.
*/
security_free_mnt_opts(sec_opts);
}
#endif
return ret;
}
/* /*
* Find a superblock for the given device / mount point. * Find a superblock for the given device / mount point.
* *
@ -1518,7 +1481,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
security_init_mnt_opts(&new_sec_opts); security_init_mnt_opts(&new_sec_opts);
if (data) { if (data) {
error = parse_security_options(data, &new_sec_opts); error = security_sb_eat_lsm_opts(data, &new_sec_opts);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
} }
@ -1537,7 +1500,6 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL); fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL); fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
security_init_mnt_opts(&fs_info->security_opts);
if (!fs_info->super_copy || !fs_info->super_for_commit) { if (!fs_info->super_copy || !fs_info->super_for_commit) {
error = -ENOMEM; error = -ENOMEM;
goto error_fs_info; goto error_fs_info;
@ -1588,16 +1550,12 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
btrfs_sb(s)->bdev_holder = fs_type; btrfs_sb(s)->bdev_holder = fs_type;
error = btrfs_fill_super(s, fs_devices, data); error = btrfs_fill_super(s, fs_devices, data);
} }
if (!error)
error = security_sb_set_mnt_opts(s, &new_sec_opts, 0, NULL);
security_free_mnt_opts(&new_sec_opts);
if (error) { if (error) {
deactivate_locked_super(s); deactivate_locked_super(s);
goto error_sec_opts; return ERR_PTR(error);
}
fs_info = btrfs_sb(s);
error = setup_security_options(fs_info, s, &new_sec_opts);
if (error) {
deactivate_locked_super(s);
goto error_sec_opts;
} }
return dget(s->s_root); return dget(s->s_root);
@ -1769,15 +1727,12 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
struct security_mnt_opts new_sec_opts; struct security_mnt_opts new_sec_opts;
security_init_mnt_opts(&new_sec_opts); security_init_mnt_opts(&new_sec_opts);
ret = parse_security_options(data, &new_sec_opts); ret = security_sb_eat_lsm_opts(data, &new_sec_opts);
if (!ret)
ret = security_sb_remount(sb, &new_sec_opts);
security_free_mnt_opts(&new_sec_opts);
if (ret) if (ret)
goto restore; goto restore;
ret = setup_security_options(fs_info, sb,
&new_sec_opts);
if (ret) {
security_free_mnt_opts(&new_sec_opts);
goto restore;
}
} }
ret = btrfs_parse_options(fs_info, data, *flags); ret = btrfs_parse_options(fs_info, data, *flags);

View File

@ -404,6 +404,7 @@ int security_sb_remount(struct super_block *sb,
{ {
return call_int_hook(sb_remount, 0, sb, opts); return call_int_hook(sb_remount, 0, sb, opts);
} }
EXPORT_SYMBOL(security_sb_remount);
int security_sb_kern_mount(struct super_block *sb) int security_sb_kern_mount(struct super_block *sb)
{ {