Skip to content

Commit

Permalink
LSM: hide struct security_mnt_opts from any generic code
Browse files Browse the repository at this point in the history
Keep void * instead, allocate on demand (in parse_str_opts, at the
moment).  Eventually both selinux and smack will be better off
with private structures with several strings in those, rather than
this "counter and two pointers to dynamically allocated arrays"
ugliness.  This commit allows to do that at leisure, without
disrupting anything outside of given module.

Changes:
	* instead of struct security_mnt_opt use an opaque pointer
initialized to NULL.
	* security_sb_eat_lsm_opts(), security_sb_parse_opts_str() and
security_free_mnt_opts() take it as var argument (i.e. as void **);
call sites are unchanged.
	* security_sb_set_mnt_opts() and security_sb_remount() take
it by value (i.e. as void *).
	* new method: ->sb_free_mnt_opts().  Takes void *, does
whatever freeing that needs to be done.
	* ->sb_set_mnt_opts() and ->sb_remount() might get NULL as
mnt_opts argument, meaning "empty".

Reviewed-by: David Howells <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed Dec 21, 2018
1 parent e3489f8 commit 204cc0c
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 92 deletions.
10 changes: 4 additions & 6 deletions fs/btrfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1472,14 +1472,13 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
struct btrfs_device *device = NULL;
struct btrfs_fs_devices *fs_devices = NULL;
struct btrfs_fs_info *fs_info = NULL;
struct security_mnt_opts new_sec_opts;
void *new_sec_opts = NULL;
fmode_t mode = FMODE_READ;
int error = 0;

if (!(flags & SB_RDONLY))
mode |= FMODE_WRITE;

security_init_mnt_opts(&new_sec_opts);
if (data) {
error = security_sb_eat_lsm_opts(data, &new_sec_opts);
if (error)
Expand Down Expand Up @@ -1551,7 +1550,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
error = btrfs_fill_super(s, fs_devices, data);
}
if (!error)
error = security_sb_set_mnt_opts(s, &new_sec_opts, 0, NULL);
error = security_sb_set_mnt_opts(s, new_sec_opts, 0, NULL);
security_free_mnt_opts(&new_sec_opts);
if (error) {
deactivate_locked_super(s);
Expand Down Expand Up @@ -1724,12 +1723,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
btrfs_remount_prepare(fs_info);

if (data) {
struct security_mnt_opts new_sec_opts;
void *new_sec_opts = NULL;

security_init_mnt_opts(&new_sec_opts);
ret = security_sb_eat_lsm_opts(data, &new_sec_opts);
if (!ret)
ret = security_sb_remount(sb, &new_sec_opts);
ret = security_sb_remount(sb, new_sec_opts);
security_free_mnt_opts(&new_sec_opts);
if (ret)
goto restore;
Expand Down
9 changes: 4 additions & 5 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -2299,7 +2299,7 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
int err;
struct super_block *sb = path->mnt->mnt_sb;
struct mount *mnt = real_mount(path->mnt);
struct security_mnt_opts opts;
void *sec_opts = NULL;

if (!check_mnt(mnt))
return -EINVAL;
Expand All @@ -2310,14 +2310,13 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
if (!can_change_locked_flags(mnt, mnt_flags))
return -EPERM;

security_init_mnt_opts(&opts);
if (data && !(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)) {
err = security_sb_eat_lsm_opts(data, &opts);
err = security_sb_eat_lsm_opts(data, &sec_opts);
if (err)
return err;
}
err = security_sb_remount(sb, &opts);
security_free_mnt_opts(&opts);
err = security_sb_remount(sb, sec_opts);
security_free_mnt_opts(&sec_opts);
if (err)
return err;

Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct nfs_parsed_mount_data {
unsigned short protocol;
} nfs_server;

struct security_mnt_opts lsm_opts;
void *lsm_opts;
struct net *net;
};

Expand Down
6 changes: 3 additions & 3 deletions fs/nfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
data->minorversion = 0;
data->need_mount = true;
data->net = current->nsproxy->net_ns;
security_init_mnt_opts(&data->lsm_opts);
data->lsm_opts = NULL;
}
return data;
}
Expand Down Expand Up @@ -2294,7 +2294,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
/* compare new mount options with old ones */
error = nfs_compare_remount_data(nfss, data);
if (!error)
error = security_sb_remount(sb, &data->lsm_opts);
error = security_sb_remount(sb, data->lsm_opts);
out:
nfs_free_parsed_mount_data(data);
return error;
Expand Down Expand Up @@ -2534,7 +2534,7 @@ int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
kflags |= SECURITY_LSM_NATIVE_LABELS;

error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
error = security_sb_set_mnt_opts(s, mount_info->parsed->lsm_opts,
kflags, &kflags_out);
if (error)
goto err;
Expand Down
12 changes: 5 additions & 7 deletions fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1247,12 +1247,10 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
struct dentry *root;
struct super_block *sb;
int error = -ENOMEM;
struct security_mnt_opts opts;

security_init_mnt_opts(&opts);
void *sec_opts = NULL;

if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
error = security_sb_eat_lsm_opts(data, &opts);
error = security_sb_eat_lsm_opts(data, &sec_opts);
if (error)
return ERR_PTR(error);
}
Expand All @@ -1275,7 +1273,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
smp_wmb();
sb->s_flags |= SB_BORN;

error = security_sb_set_mnt_opts(sb, &opts, 0, NULL);
error = security_sb_set_mnt_opts(sb, sec_opts, 0, NULL);
if (error)
goto out_sb;

Expand All @@ -1295,13 +1293,13 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
"negative value (%lld)\n", type->name, sb->s_maxbytes);

up_write(&sb->s_umount);
security_free_mnt_opts(&opts);
security_free_mnt_opts(&sec_opts);
return root;
out_sb:
dput(root);
deactivate_locked_super(sb);
out_free_secdata:
security_free_mnt_opts(&opts);
security_free_mnt_opts(&sec_opts);
return ERR_PTR(error);
}

Expand Down
11 changes: 6 additions & 5 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -1461,9 +1461,9 @@ union security_list_options {

int (*sb_alloc_security)(struct super_block *sb);
void (*sb_free_security)(struct super_block *sb);
int (*sb_eat_lsm_opts)(char *orig, struct security_mnt_opts *opts);
int (*sb_remount)(struct super_block *sb,
struct security_mnt_opts *opts);
void (*sb_free_mnt_opts)(void *mnt_opts);
int (*sb_eat_lsm_opts)(char *orig, void **mnt_opts);
int (*sb_remount)(struct super_block *sb, void *mnt_opts);
int (*sb_kern_mount)(struct super_block *sb);
int (*sb_show_options)(struct seq_file *m, struct super_block *sb);
int (*sb_statfs)(struct dentry *dentry);
Expand All @@ -1472,14 +1472,14 @@ union security_list_options {
int (*sb_umount)(struct vfsmount *mnt, int flags);
int (*sb_pivotroot)(const struct path *old_path, const struct path *new_path);
int (*sb_set_mnt_opts)(struct super_block *sb,
struct security_mnt_opts *opts,
void *mnt_opts,
unsigned long kern_flags,
unsigned long *set_kern_flags);
int (*sb_clone_mnt_opts)(const struct super_block *oldsb,
struct super_block *newsb,
unsigned long kern_flags,
unsigned long *set_kern_flags);
int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts);
int (*sb_parse_opts_str)(char *options, void **mnt_opts);
int (*dentry_init_security)(struct dentry *dentry, int mode,
const struct qstr *name, void **ctx,
u32 *ctxlen);
Expand Down Expand Up @@ -1801,6 +1801,7 @@ struct security_hook_heads {
struct hlist_head bprm_committed_creds;
struct hlist_head sb_alloc_security;
struct hlist_head sb_free_security;
struct hlist_head sb_free_mnt_opts;
struct hlist_head sb_eat_lsm_opts;
struct hlist_head sb_remount;
struct hlist_head sb_kern_mount;
Expand Down
43 changes: 10 additions & 33 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,26 +192,6 @@ int call_lsm_notifier(enum lsm_event event, void *data);
int register_lsm_notifier(struct notifier_block *nb);
int unregister_lsm_notifier(struct notifier_block *nb);

static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
{
opts->mnt_opts = NULL;
opts->mnt_opts_flags = NULL;
opts->num_mnt_opts = 0;
}

static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
{
int i;
if (opts->mnt_opts)
for (i = 0; i < opts->num_mnt_opts; i++)
kfree(opts->mnt_opts[i]);
kfree(opts->mnt_opts);
opts->mnt_opts = NULL;
kfree(opts->mnt_opts_flags);
opts->mnt_opts_flags = NULL;
opts->num_mnt_opts = 0;
}

/* prototypes */
extern int security_init(void);

Expand Down Expand Up @@ -248,8 +228,9 @@ void security_bprm_committing_creds(struct linux_binprm *bprm);
void security_bprm_committed_creds(struct linux_binprm *bprm);
int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
int security_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts);
int security_sb_remount(struct super_block *sb, struct security_mnt_opts *opts);
void security_free_mnt_opts(void **mnt_opts);
int security_sb_eat_lsm_opts(char *options, void **mnt_opts);
int security_sb_remount(struct super_block *sb, void *mnt_opts);
int security_sb_kern_mount(struct super_block *sb);
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
int security_sb_statfs(struct dentry *dentry);
Expand All @@ -258,14 +239,14 @@ int security_sb_mount(const char *dev_name, const struct path *path,
int security_sb_umount(struct vfsmount *mnt, int flags);
int security_sb_pivotroot(const struct path *old_path, const struct path *new_path);
int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts,
void *mnt_opts,
unsigned long kern_flags,
unsigned long *set_kern_flags);
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb,
unsigned long kern_flags,
unsigned long *set_kern_flags);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
int security_sb_parse_opts_str(char *options, void **mnt_opts);
int security_dentry_init_security(struct dentry *dentry, int mode,
const struct qstr *name, void **ctx,
u32 *ctxlen);
Expand Down Expand Up @@ -421,11 +402,7 @@ static inline int unregister_lsm_notifier(struct notifier_block *nb)
return 0;
}

static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
{
}

static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
static inline void security_free_mnt_opts(void **mnt_opts)
{
}

Expand Down Expand Up @@ -556,13 +533,13 @@ static inline void security_sb_free(struct super_block *sb)
{ }

static inline int security_sb_eat_lsm_opts(char *options,
struct security_mnt_opts *opts)
void **mnt_opts)
{
return 0;
}

static inline int security_sb_remount(struct super_block *sb,
struct security_mnt_opts *opts)
void *mnt_opts)
{
return 0;
}
Expand Down Expand Up @@ -602,7 +579,7 @@ static inline int security_sb_pivotroot(const struct path *old_path,
}

static inline int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts,
void *mnt_opts,
unsigned long kern_flags,
unsigned long *set_kern_flags)
{
Expand All @@ -617,7 +594,7 @@ static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb,
return 0;
}

static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
static inline int security_sb_parse_opts_str(char *options, void **mnt_opts)
{
return 0;
}
Expand Down
27 changes: 18 additions & 9 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,16 +384,25 @@ void security_sb_free(struct super_block *sb)
call_void_hook(sb_free_security, sb);
}

int security_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts)
void security_free_mnt_opts(void **mnt_opts)
{
return call_int_hook(sb_eat_lsm_opts, 0, options, opts);
if (!*mnt_opts)
return;
call_void_hook(sb_free_mnt_opts, *mnt_opts);
*mnt_opts = NULL;
}
EXPORT_SYMBOL(security_free_mnt_opts);

int security_sb_eat_lsm_opts(char *options, void **mnt_opts)
{
return call_int_hook(sb_eat_lsm_opts, 0, options, mnt_opts);
}
EXPORT_SYMBOL(security_sb_eat_lsm_opts);

int security_sb_remount(struct super_block *sb,
struct security_mnt_opts *opts)
void *mnt_opts)
{
return call_int_hook(sb_remount, 0, sb, opts);
return call_int_hook(sb_remount, 0, sb, mnt_opts);
}
EXPORT_SYMBOL(security_sb_remount);

Expand Down Expand Up @@ -429,13 +438,13 @@ int security_sb_pivotroot(const struct path *old_path, const struct path *new_pa
}

int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts,
void *mnt_opts,
unsigned long kern_flags,
unsigned long *set_kern_flags)
{
return call_int_hook(sb_set_mnt_opts,
opts->num_mnt_opts ? -EOPNOTSUPP : 0, sb,
opts, kern_flags, set_kern_flags);
mnt_opts ? -EOPNOTSUPP : 0, sb,
mnt_opts, kern_flags, set_kern_flags);
}
EXPORT_SYMBOL(security_sb_set_mnt_opts);

Expand All @@ -449,9 +458,9 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,
}
EXPORT_SYMBOL(security_sb_clone_mnt_opts);

int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
int security_sb_parse_opts_str(char *options, void **mnt_opts)
{
return call_int_hook(sb_parse_opts_str, 0, options, opts);
return call_int_hook(sb_parse_opts_str, 0, options, mnt_opts);
}
EXPORT_SYMBOL(security_sb_parse_opts_str);

Expand Down
Loading

0 comments on commit 204cc0c

Please sign in to comment.