From 6466f3d193a99426db067855345e763de2160f1c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Dec 2018 22:55:40 -0500 Subject: smack: make smack_parse_opts_str() clean up on failure fixes e.g. a btrfs leak... Reviewed-by: David Howells Signed-off-by: Al Viro --- security/smack/smack_lsm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'security/smack') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 81fb4c1631e9..73e41797960e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -735,6 +735,7 @@ out_err: kfree(fshat); kfree(fsroot); kfree(fstransmute); + security_free_mnt_opts(opts); return rc; } -- cgit v1.2.3-55-g7522 From 6be8750b4cba8c37170f46b29841d112f1be749b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Dec 2018 22:42:44 -0500 Subject: LSM: lift parsing LSM options into the caller of ->sb_kern_mount() This paves the way for retaining the LSM options from a common filesystem mount context during a mount parameter parsing phase to be instituted prior to actual mount/reconfiguration actions. Reviewed-by: David Howells Signed-off-by: Al Viro --- fs/super.c | 24 ++++++++++++++++-------- include/linux/lsm_hooks.h | 3 ++- include/linux/security.h | 6 ++++-- security/security.c | 5 +++-- security/selinux/hooks.c | 24 +++--------------------- security/smack/smack_lsm.c | 23 +++-------------------- 6 files changed, 31 insertions(+), 54 deletions(-) (limited to 'security/smack') diff --git a/fs/super.c b/fs/super.c index 6654de035893..8d9c9199832d 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1246,17 +1246,26 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) { struct dentry *root; struct super_block *sb; - char *secdata = NULL; int error = -ENOMEM; + struct security_mnt_opts opts; + + security_init_mnt_opts(&opts); if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { - secdata = alloc_secdata(); + char *secdata = alloc_secdata(); if (!secdata) - goto out; + return ERR_PTR(-ENOMEM); error = security_sb_copy_data(data, secdata); + if (error) { + free_secdata(secdata); + return ERR_PTR(error); + } + + error = security_sb_parse_opts_str(secdata, &opts); + free_secdata(secdata); if (error) - goto out_free_secdata; + return ERR_PTR(error); } root = type->mount(type, flags, name, data); @@ -1277,7 +1286,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_kern_mount(sb, flags, secdata); + error = security_sb_kern_mount(sb, flags, &opts); if (error) goto out_sb; @@ -1291,14 +1300,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); - free_secdata(secdata); + security_free_mnt_opts(&opts); return root; out_sb: dput(root); deactivate_locked_super(sb); out_free_secdata: - free_secdata(secdata); -out: + security_free_mnt_opts(&opts); return ERR_PTR(error); } diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index aaeb7fa24dc4..c7f67341fd1d 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1463,7 +1463,8 @@ union security_list_options { void (*sb_free_security)(struct super_block *sb); int (*sb_copy_data)(char *orig, char *copy); int (*sb_remount)(struct super_block *sb, void *data); - int (*sb_kern_mount)(struct super_block *sb, int flags, void *data); + int (*sb_kern_mount)(struct super_block *sb, int flags, + struct security_mnt_opts *opts); int (*sb_show_options)(struct seq_file *m, struct super_block *sb); int (*sb_statfs)(struct dentry *dentry); int (*sb_mount)(const char *dev_name, const struct path *path, diff --git a/include/linux/security.h b/include/linux/security.h index d170a5b031f3..f2f88e41f35f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -250,7 +250,8 @@ int security_sb_alloc(struct super_block *sb); void security_sb_free(struct super_block *sb); int security_sb_copy_data(char *orig, char *copy); int security_sb_remount(struct super_block *sb, void *data); -int security_sb_kern_mount(struct super_block *sb, int flags, void *data); +int security_sb_kern_mount(struct super_block *sb, int flags, + struct security_mnt_opts *opts); int security_sb_show_options(struct seq_file *m, struct super_block *sb); int security_sb_statfs(struct dentry *dentry); int security_sb_mount(const char *dev_name, const struct path *path, @@ -565,7 +566,8 @@ static inline int security_sb_remount(struct super_block *sb, void *data) return 0; } -static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data) +static inline int security_sb_kern_mount(struct super_block *sb, int flags, + struct security_mnt_opts *opts) { return 0; } diff --git a/security/security.c b/security/security.c index 04d173eb93f6..b5fc8e1e849c 100644 --- a/security/security.c +++ b/security/security.c @@ -395,9 +395,10 @@ int security_sb_remount(struct super_block *sb, void *data) return call_int_hook(sb_remount, 0, sb, data); } -int security_sb_kern_mount(struct super_block *sb, int flags, void *data) +int security_sb_kern_mount(struct super_block *sb, int flags, + struct security_mnt_opts *opts) { - return call_int_hook(sb_kern_mount, 0, sb, flags, data); + return call_int_hook(sb_kern_mount, 0, sb, flags, opts); } int security_sb_show_options(struct seq_file *m, struct super_block *sb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4bd6f9435e2f..ba229d4a64d3 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2897,30 +2897,12 @@ out_bad_option: goto out_free_opts; } -static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) +static int selinux_sb_kern_mount(struct super_block *sb, int flags, + struct security_mnt_opts *opts) { - char *options = data; const struct cred *cred = current_cred(); struct common_audit_data ad; - int rc = 0; - struct security_mnt_opts opts; - - security_init_mnt_opts(&opts); - - if (!data) - goto out; - - BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA); - - rc = selinux_parse_opts_str(options, &opts); - if (rc) - goto out_err; - -out: - rc = selinux_set_mnt_opts(sb, &opts, 0, NULL); - -out_err: - security_free_mnt_opts(&opts); + int rc = selinux_set_mnt_opts(sb, opts, 0, NULL); if (rc) return rc; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 73e41797960e..1d465ae3d11c 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -859,27 +859,10 @@ static int smack_set_mnt_opts(struct super_block *sb, * * Returns 0 on success, an error code on failure */ -static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) +static int smack_sb_kern_mount(struct super_block *sb, int flags, + struct security_mnt_opts *opts) { - int rc = 0; - char *options = data; - struct security_mnt_opts opts; - - security_init_mnt_opts(&opts); - - if (!options) - goto out; - - rc = smack_parse_opts_str(options, &opts); - if (rc) - goto out_err; - -out: - rc = smack_set_mnt_opts(sb, &opts, 0, NULL); - -out_err: - security_free_mnt_opts(&opts); - return rc; + return smack_set_mnt_opts(sb, opts, 0, NULL); } /** -- cgit v1.2.3-55-g7522 From a10d7c22b34bcf744679019269bfb33ebf0b75ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 5 Dec 2018 11:58:35 -0500 Subject: LSM: split ->sb_set_mnt_opts() out of ->sb_kern_mount() ... leaving the "is it kernel-internal" logics in the caller. Reviewed-by: David Howells Signed-off-by: Al Viro --- fs/super.c | 8 +++++++- include/linux/lsm_hooks.h | 3 +-- include/linux/security.h | 6 ++---- security/security.c | 5 ++--- security/selinux/hooks.c | 10 +--------- security/smack/smack_lsm.c | 15 --------------- 6 files changed, 13 insertions(+), 34 deletions(-) (limited to 'security/smack') diff --git a/fs/super.c b/fs/super.c index d571527cb8b8..1f75fe312597 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1275,10 +1275,16 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) smp_wmb(); sb->s_flags |= SB_BORN; - error = security_sb_kern_mount(sb, flags, &opts); + error = security_sb_set_mnt_opts(sb, &opts, 0, NULL); if (error) goto out_sb; + if (!(flags & MS_KERNMOUNT)) { + error = security_sb_kern_mount(sb); + if (error) + goto out_sb; + } + /* * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE * but s_maxbytes was an unsigned long long for many releases. Throw diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index e1a12a1e2b32..f432123af0e3 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1464,8 +1464,7 @@ union security_list_options { int (*sb_copy_data)(char *orig, char *copy); int (*sb_remount)(struct super_block *sb, struct security_mnt_opts *opts); - int (*sb_kern_mount)(struct super_block *sb, int flags, - struct security_mnt_opts *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); int (*sb_mount)(const char *dev_name, const struct path *path, diff --git a/include/linux/security.h b/include/linux/security.h index 262e59838803..d00093363570 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -250,8 +250,7 @@ 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); -int security_sb_kern_mount(struct super_block *sb, int flags, - struct security_mnt_opts *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); int security_sb_mount(const char *dev_name, const struct path *path, @@ -568,8 +567,7 @@ static inline int security_sb_remount(struct super_block *sb, return 0; } -static inline int security_sb_kern_mount(struct super_block *sb, int flags, - struct security_mnt_opts *opts) +static inline int security_sb_kern_mount(struct super_block *sb) { return 0; } diff --git a/security/security.c b/security/security.c index 02c656dd5c0c..afb05646d41b 100644 --- a/security/security.c +++ b/security/security.c @@ -405,10 +405,9 @@ int security_sb_remount(struct super_block *sb, return call_int_hook(sb_remount, 0, sb, opts); } -int security_sb_kern_mount(struct super_block *sb, int flags, - struct security_mnt_opts *opts) +int security_sb_kern_mount(struct super_block *sb) { - return call_int_hook(sb_kern_mount, 0, sb, flags, opts); + return call_int_hook(sb_kern_mount, 0, sb); } int security_sb_show_options(struct seq_file *m, struct super_block *sb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ba3e2917bd24..59b164d7134d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2874,18 +2874,10 @@ out_bad_option: return -EINVAL; } -static int selinux_sb_kern_mount(struct super_block *sb, int flags, - struct security_mnt_opts *opts) +static int selinux_sb_kern_mount(struct super_block *sb) { const struct cred *cred = current_cred(); struct common_audit_data ad; - int rc = selinux_set_mnt_opts(sb, opts, 0, NULL); - if (rc) - return rc; - - /* Allow all mounts performed by the kernel */ - if (flags & MS_KERNMOUNT) - return 0; ad.type = LSM_AUDIT_DATA_DENTRY; ad.u.dentry = sb->s_root; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1d465ae3d11c..50e6e88bfe70 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -851,20 +851,6 @@ static int smack_set_mnt_opts(struct super_block *sb, return 0; } -/** - * smack_sb_kern_mount - Smack specific mount processing - * @sb: the file system superblock - * @flags: the mount flags - * @data: the smack mount options - * - * Returns 0 on success, an error code on failure - */ -static int smack_sb_kern_mount(struct super_block *sb, int flags, - struct security_mnt_opts *opts) -{ - return smack_set_mnt_opts(sb, opts, 0, NULL); -} - /** * smack_sb_statfs - Smack check on statfs * @dentry: identifies the file system in question @@ -4652,7 +4638,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, smack_sb_free_security), LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), - LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount), LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), -- cgit v1.2.3-55-g7522 From 5b4002391153acebce2557af318bbdc17e235134 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Dec 2018 20:13:29 -0500 Subject: LSM: turn sb_eat_lsm_opts() into a method Kill ->sb_copy_data() - it's used only in combination with immediately following ->sb_parse_opts_str(). Turn that combination into a new method. This is just a mechanical move - cleanups will be the next step. Reviewed-by: David Howells Signed-off-by: Al Viro --- include/linux/lsm_hooks.h | 4 ++-- security/security.c | 11 +---------- security/selinux/hooks.c | 16 +++++++++++++++- security/smack/smack_lsm.c | 16 +++++++++++++++- 4 files changed, 33 insertions(+), 14 deletions(-) (limited to 'security/smack') diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index f432123af0e3..c418909c178c 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1461,7 +1461,7 @@ union security_list_options { int (*sb_alloc_security)(struct super_block *sb); void (*sb_free_security)(struct super_block *sb); - int (*sb_copy_data)(char *orig, char *copy); + int (*sb_eat_lsm_opts)(char *orig, struct security_mnt_opts *opts); int (*sb_remount)(struct super_block *sb, struct security_mnt_opts *opts); int (*sb_kern_mount)(struct super_block *sb); @@ -1801,7 +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_copy_data; + struct hlist_head sb_eat_lsm_opts; struct hlist_head sb_remount; struct hlist_head sb_kern_mount; struct hlist_head sb_show_options; diff --git a/security/security.c b/security/security.c index 3d8b72904e00..feb18c925349 100644 --- a/security/security.c +++ b/security/security.c @@ -386,16 +386,7 @@ void security_sb_free(struct super_block *sb) int security_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) { - char *s = (char *)get_zeroed_page(GFP_KERNEL); - int err; - - if (!s) - return -ENOMEM; - err = call_int_hook(sb_copy_data, 0, options, s); - if (!err) - err = call_int_hook(sb_parse_opts_str, 0, s, opts); - free_page((unsigned long)s); - return err; + return call_int_hook(sb_eat_lsm_opts, 0, options, opts); } EXPORT_SYMBOL(security_sb_eat_lsm_opts); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 630fe8883957..ce0511f024e0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2810,6 +2810,20 @@ out: return rc; } +static int selinux_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) +{ + char *s = (char *)get_zeroed_page(GFP_KERNEL); + int err; + + if (!s) + return -ENOMEM; + err = selinux_sb_copy_data(options, s); + if (!err) + err = selinux_parse_opts_str(s, opts); + free_page((unsigned long)s); + return err; +} + static int selinux_sb_remount(struct super_block *sb, struct security_mnt_opts *opts) { @@ -6863,7 +6877,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), - LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data), + LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts), LSM_HOOK_INIT(sb_remount, selinux_sb_remount), LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount), LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options), diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 50e6e88bfe70..835cca277c2a 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -739,6 +739,20 @@ out_err: return rc; } +static int smack_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) +{ + char *s = (char *)get_zeroed_page(GFP_KERNEL); + int err; + + if (!s) + return -ENOMEM; + err = smack_sb_copy_data(options, s); + if (!err) + err = smack_parse_opts_str(s, opts); + free_page((unsigned long)s); + return err; +} + /** * smack_set_mnt_opts - set Smack specific mount options * @sb: the file system superblock @@ -4637,7 +4651,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, smack_sb_free_security), - LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), + LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts), LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), -- cgit v1.2.3-55-g7522 From 204cc0ccf1d49c6292aeef4c8edd1b3d10ff933c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 13 Dec 2018 13:41:47 -0500 Subject: LSM: hide struct security_mnt_opts from any generic code 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 Signed-off-by: Al Viro --- fs/btrfs/super.c | 10 ++++----- fs/namespace.c | 9 ++++---- fs/nfs/internal.h | 2 +- fs/nfs/super.c | 6 +++--- fs/super.c | 12 +++++------ include/linux/lsm_hooks.h | 11 +++++----- include/linux/security.h | 43 +++++++++----------------------------- security/security.c | 27 ++++++++++++++++-------- security/selinux/hooks.c | 52 +++++++++++++++++++++++++++++++++------------- security/smack/smack_lsm.c | 38 ++++++++++++++++++++++++++------- 10 files changed, 118 insertions(+), 92 deletions(-) (limited to 'security/smack') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3b04e7735b5f..e90c4616ed6a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -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) @@ -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); @@ -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; diff --git a/fs/namespace.c b/fs/namespace.c index 39aca7b69c2e..badfd287358c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -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; @@ -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; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8357ff69962f..97e1dcefe561 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -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; }; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 300bdd1d4a09..1943de8f9d29 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -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; } @@ -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; @@ -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; diff --git a/fs/super.c b/fs/super.c index 1f75fe312597..a5511c4ba69b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -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); } @@ -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; @@ -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); } diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index c418909c178c..a9c541f5732e 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -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); @@ -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); @@ -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; diff --git a/include/linux/security.h b/include/linux/security.h index d00093363570..4bca0be95b7a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -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); @@ -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); @@ -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); @@ -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) { } @@ -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; } @@ -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) { @@ -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; } diff --git a/security/security.c b/security/security.c index feb18c925349..b7a5a0051807 100644 --- a/security/security.c +++ b/security/security.c @@ -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); @@ -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); @@ -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); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 11cf2feb27b3..caf7ca7abfc1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -433,6 +433,19 @@ static void superblock_free_security(struct super_block *sb) kfree(sbsec); } +static void selinux_free_mnt_opts(void *mnt_opts) +{ + struct security_mnt_opts *opts = mnt_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); + kfree(opts->mnt_opts_flags); + kfree(opts); +} + static inline int inode_doinit(struct inode *inode) { return inode_doinit_with_dentry(inode, NULL); @@ -616,7 +629,7 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, * labeling information. */ static int selinux_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, + void *mnt_opts, unsigned long kern_flags, unsigned long *set_kern_flags) { @@ -628,9 +641,10 @@ static int selinux_set_mnt_opts(struct super_block *sb, struct inode_security_struct *root_isec; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 defcontext_sid = 0; - char **mount_options = opts->mnt_opts; - int *flags = opts->mnt_opts_flags; - int num_opts = opts->num_mnt_opts; + struct security_mnt_opts *opts = mnt_opts; + char **mount_options = opts ? opts->mnt_opts : NULL; + int *flags = opts ? opts->mnt_opts_flags : NULL; + int num_opts = opts ? opts->num_mnt_opts : 0; mutex_lock(&sbsec->lock); @@ -982,12 +996,20 @@ out: } static int selinux_parse_opts_str(char *options, - struct security_mnt_opts *opts) + void **mnt_opts) { char *p; char *context = NULL, *defcontext = NULL; char *fscontext = NULL, *rootcontext = NULL; int rc, num_mnt_opts = 0; + struct security_mnt_opts *opts = *mnt_opts; + + if (!opts) { + opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL); + *mnt_opts = opts; + if (!opts) + return -ENOMEM; + } opts->num_mnt_opts = 0; @@ -1094,7 +1116,7 @@ static int selinux_parse_opts_str(char *options, return 0; out_err: - security_free_mnt_opts(opts); + security_free_mnt_opts(mnt_opts); kfree(context); kfree(defcontext); kfree(fscontext); @@ -2714,7 +2736,7 @@ out: return rc; } -static int selinux_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) +static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) { char *s = (char *)get_zeroed_page(GFP_KERNEL); int err; @@ -2723,14 +2745,14 @@ static int selinux_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts return -ENOMEM; err = selinux_sb_copy_data(options, s); if (!err) - err = selinux_parse_opts_str(s, opts); + err = selinux_parse_opts_str(s, mnt_opts); free_page((unsigned long)s); return err; } -static int selinux_sb_remount(struct super_block *sb, - struct security_mnt_opts *opts) +static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) { + struct security_mnt_opts *opts = mnt_opts; int i, *flags; char **mount_options; struct superblock_security_struct *sbsec = sb->s_security; @@ -2738,6 +2760,9 @@ static int selinux_sb_remount(struct super_block *sb, if (!(sbsec->flags & SE_SBINITIALIZED)) return 0; + if (!opts) + return 0; + mount_options = opts->mnt_opts; flags = opts->mnt_opts_flags; @@ -6782,6 +6807,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts), + LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts), LSM_HOOK_INIT(sb_remount, selinux_sb_remount), LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount), LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options), @@ -7051,11 +7077,7 @@ static __init int selinux_init(void) static void delayed_superblock_init(struct super_block *sb, void *unused) { - struct security_mnt_opts opts; - - security_init_mnt_opts(&opts); - selinux_set_mnt_opts(sb, &opts, 0, NULL); - security_free_mnt_opts(&opts); + selinux_set_mnt_opts(sb, NULL, 0, NULL); } void selinux_complete_init(void) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 835cca277c2a..81a8112975d4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -567,6 +567,19 @@ static void smack_sb_free_security(struct super_block *sb) sb->s_security = NULL; } +static void smack_free_mnt_opts(void *mnt_opts) +{ + struct security_mnt_opts *opts = mnt_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); + kfree(opts->mnt_opts_flags); + kfree(opts); +} + /** * smack_sb_copy_data - copy mount options data for processing * @orig: where to start @@ -624,8 +637,9 @@ static int smack_sb_copy_data(char *orig, char *smackopts) * converts Smack specific mount options to generic security option format */ static int smack_parse_opts_str(char *options, - struct security_mnt_opts *opts) + void **mnt_opts) { + struct security_mnt_opts *opts = *mnt_opts; char *p; char *fsdefault = NULL; char *fsfloor = NULL; @@ -636,11 +650,17 @@ static int smack_parse_opts_str(char *options, int num_mnt_opts = 0; int token; - opts->num_mnt_opts = 0; - if (!options) return 0; + if (!opts) { + opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL); + *mnt_opts = opts; + if (!opts) + return -ENOMEM; + } + opts->num_mnt_opts = 0; + while ((p = strsep(&options, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -735,11 +755,11 @@ out_err: kfree(fshat); kfree(fsroot); kfree(fstransmute); - security_free_mnt_opts(opts); + security_free_mnt_opts(mnt_opts); return rc; } -static int smack_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) +static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) { char *s = (char *)get_zeroed_page(GFP_KERNEL); int err; @@ -748,7 +768,7 @@ static int smack_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) return -ENOMEM; err = smack_sb_copy_data(options, s); if (!err) - err = smack_parse_opts_str(s, opts); + err = smack_parse_opts_str(s, mnt_opts); free_page((unsigned long)s); return err; } @@ -766,7 +786,7 @@ static int smack_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts) * labels. */ static int smack_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, + void *mnt_opts, unsigned long kern_flags, unsigned long *set_kern_flags) { @@ -776,7 +796,8 @@ static int smack_set_mnt_opts(struct super_block *sb, struct inode_smack *isp; struct smack_known *skp; int i; - int num_opts = opts->num_mnt_opts; + struct security_mnt_opts *opts = mnt_opts; + int num_opts = opts ? opts->num_mnt_opts : 0; int transmute = 0; if (sp->smk_flags & SMK_SB_INITIALIZED) @@ -4651,6 +4672,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), LSM_HOOK_INIT(sb_free_security, smack_sb_free_security), + LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts), LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts), LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), -- cgit v1.2.3-55-g7522 From 12085b14a4440a6d12ff7966702c010df87caef0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 13 Dec 2018 15:18:05 -0500 Subject: smack: switch to private smack_mnt_opts Reviewed-by: David Howells Signed-off-by: Al Viro --- security/smack/smack_lsm.c | 157 ++++++++++++++++----------------------------- 1 file changed, 55 insertions(+), 102 deletions(-) (limited to 'security/smack') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 81a8112975d4..99aec9f42be3 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -567,16 +567,18 @@ static void smack_sb_free_security(struct super_block *sb) sb->s_security = NULL; } +struct smack_mnt_opts { + const char *fsdefault, *fsfloor, *fshat, *fsroot, *fstransmute; +}; + static void smack_free_mnt_opts(void *mnt_opts) { - struct security_mnt_opts *opts = mnt_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); - kfree(opts->mnt_opts_flags); + struct smack_mnt_opts *opts = mnt_opts; + kfree(opts->fsdefault); + kfree(opts->fsfloor); + kfree(opts->fshat); + kfree(opts->fsroot); + kfree(opts->fstransmute); kfree(opts); } @@ -639,28 +641,14 @@ static int smack_sb_copy_data(char *orig, char *smackopts) static int smack_parse_opts_str(char *options, void **mnt_opts) { - struct security_mnt_opts *opts = *mnt_opts; + struct smack_mnt_opts *opts = *mnt_opts; char *p; - char *fsdefault = NULL; - char *fsfloor = NULL; - char *fshat = NULL; - char *fsroot = NULL; - char *fstransmute = NULL; int rc = -ENOMEM; - int num_mnt_opts = 0; int token; if (!options) return 0; - if (!opts) { - opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL); - *mnt_opts = opts; - if (!opts) - return -ENOMEM; - } - opts->num_mnt_opts = 0; - while ((p = strsep(&options, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -669,40 +657,46 @@ static int smack_parse_opts_str(char *options, token = match_token(p, smk_mount_tokens, args); + if (!opts) { + opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); + if (!opts) + return -ENOMEM; + } + switch (token) { case Opt_fsdefault: - if (fsdefault) + if (opts->fsdefault) goto out_opt_err; - fsdefault = match_strdup(&args[0]); - if (!fsdefault) + opts->fsdefault = match_strdup(&args[0]); + if (!opts->fsdefault) goto out_err; break; case Opt_fsfloor: - if (fsfloor) + if (opts->fsfloor) goto out_opt_err; - fsfloor = match_strdup(&args[0]); - if (!fsfloor) + opts->fsfloor = match_strdup(&args[0]); + if (!opts->fsfloor) goto out_err; break; case Opt_fshat: - if (fshat) + if (opts->fshat) goto out_opt_err; - fshat = match_strdup(&args[0]); - if (!fshat) + opts->fshat = match_strdup(&args[0]); + if (!opts->fshat) goto out_err; break; case Opt_fsroot: - if (fsroot) + if (opts->fsroot) goto out_opt_err; - fsroot = match_strdup(&args[0]); - if (!fsroot) + opts->fsroot = match_strdup(&args[0]); + if (!opts->fsroot) goto out_err; break; case Opt_fstransmute: - if (fstransmute) + if (opts->fstransmute) goto out_opt_err; - fstransmute = match_strdup(&args[0]); - if (!fstransmute) + opts->fstransmute = match_strdup(&args[0]); + if (!opts->fstransmute) goto out_err; break; default: @@ -711,38 +705,7 @@ static int smack_parse_opts_str(char *options, goto out_err; } } - - opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *), GFP_KERNEL); - if (!opts->mnt_opts) - goto out_err; - - opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), - GFP_KERNEL); - if (!opts->mnt_opts_flags) - goto out_err; - - if (fsdefault) { - opts->mnt_opts[num_mnt_opts] = fsdefault; - opts->mnt_opts_flags[num_mnt_opts++] = FSDEFAULT_MNT; - } - if (fsfloor) { - opts->mnt_opts[num_mnt_opts] = fsfloor; - opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT; - } - if (fshat) { - opts->mnt_opts[num_mnt_opts] = fshat; - opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT; - } - if (fsroot) { - opts->mnt_opts[num_mnt_opts] = fsroot; - opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT; - } - if (fstransmute) { - opts->mnt_opts[num_mnt_opts] = fstransmute; - opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT; - } - - opts->num_mnt_opts = num_mnt_opts; + *mnt_opts = opts; return 0; out_opt_err: @@ -750,12 +713,8 @@ out_opt_err: pr_warn("Smack: duplicate mount options\n"); out_err: - kfree(fsdefault); - kfree(fsfloor); - kfree(fshat); - kfree(fsroot); - kfree(fstransmute); - security_free_mnt_opts(mnt_opts); + if (opts) + smack_free_mnt_opts(opts); return rc; } @@ -795,10 +754,8 @@ static int smack_set_mnt_opts(struct super_block *sb, struct superblock_smack *sp = sb->s_security; struct inode_smack *isp; struct smack_known *skp; - int i; - struct security_mnt_opts *opts = mnt_opts; - int num_opts = opts ? opts->num_mnt_opts : 0; - int transmute = 0; + struct smack_mnt_opts *opts = mnt_opts; + bool transmute = false; if (sp->smk_flags & SMK_SB_INITIALIZED) return 0; @@ -807,7 +764,7 @@ static int smack_set_mnt_opts(struct super_block *sb, /* * Unprivileged mounts don't get to specify Smack values. */ - if (num_opts) + if (opts) return -EPERM; /* * Unprivileged mounts get root and default from the caller. @@ -823,48 +780,44 @@ static int smack_set_mnt_opts(struct super_block *sb, if (sb->s_user_ns != &init_user_ns && sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC && sb->s_magic != RAMFS_MAGIC) { - transmute = 1; + transmute = true; sp->smk_flags |= SMK_SB_UNTRUSTED; } } sp->smk_flags |= SMK_SB_INITIALIZED; - for (i = 0; i < num_opts; i++) { - switch (opts->mnt_opts_flags[i]) { - case FSDEFAULT_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); + if (opts) { + if (opts->fsdefault) { + skp = smk_import_entry(opts->fsdefault, 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_default = skp; - break; - case FSFLOOR_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); + } + if (opts->fsfloor) { + skp = smk_import_entry(opts->fsfloor, 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_floor = skp; - break; - case FSHAT_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); + } + if (opts->fshat) { + skp = smk_import_entry(opts->fshat, 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_hat = skp; - break; - case FSROOT_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); + } + if (opts->fsroot) { + skp = smk_import_entry(opts->fsroot, 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_root = skp; - break; - case FSTRANS_MNT: - skp = smk_import_entry(opts->mnt_opts[i], 0); + } + if (opts->fstransmute) { + skp = smk_import_entry(opts->fstransmute, 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_root = skp; - transmute = 1; - break; - default: - break; + transmute = true; } } -- cgit v1.2.3-55-g7522 From 757cbe597fe8490c7c0a9650ebe5d60195f151d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 14 Dec 2018 23:42:21 -0500 Subject: LSM: new method: ->sb_add_mnt_opt() Adding options to growing mnt_opts. NFS kludge with passing context= down into non-text-options mount switched to it, and with that the last use of ->sb_parse_opts_str() is gone. Reviewed-by: David Howells Signed-off-by: Al Viro --- fs/nfs/super.c | 9 ++------- include/linux/lsm_hooks.h | 5 +++-- include/linux/security.h | 6 ++++-- security/security.c | 8 +++++--- security/selinux/hooks.c | 45 +++++++++++++++++++-------------------------- security/smack/smack_lsm.c | 1 - 6 files changed, 33 insertions(+), 41 deletions(-) (limited to 'security/smack') diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1943de8f9d29..073eec2366f8 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2070,14 +2070,9 @@ static int nfs23_validate_mount_data(void *options, if (data->context[0]){ #ifdef CONFIG_SECURITY_SELINUX int rc; - char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL); - if (!opts_str) - return -ENOMEM; - strcpy(opts_str, "context="); data->context[NFS_MAX_CONTEXT_LEN] = '\0'; - strcat(opts_str, &data->context[0]); - rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts); - kfree(opts_str); + rc = security_add_mnt_opt("context", data->context, + strlen(data->context), &args->lsm_opts); if (rc) return rc; #else diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index a9c541f5732e..9a0bdf91e646 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1479,7 +1479,8 @@ union security_list_options { struct super_block *newsb, unsigned long kern_flags, unsigned long *set_kern_flags); - int (*sb_parse_opts_str)(char *options, void **mnt_opts); + int (*sb_add_mnt_opt)(const char *option, const char *val, int len, + void **mnt_opts); int (*dentry_init_security)(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, u32 *ctxlen); @@ -1812,7 +1813,7 @@ struct security_hook_heads { struct hlist_head sb_pivotroot; struct hlist_head sb_set_mnt_opts; struct hlist_head sb_clone_mnt_opts; - struct hlist_head sb_parse_opts_str; + struct hlist_head sb_add_mnt_opt; struct hlist_head dentry_init_security; struct hlist_head dentry_create_files_as; #ifdef CONFIG_SECURITY_PATH diff --git a/include/linux/security.h b/include/linux/security.h index ae8d5ac5882e..dbfb5a66babb 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -240,7 +240,8 @@ 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, void **mnt_opts); +int security_add_mnt_opt(const char *option, const char *val, + int len, void **mnt_opts); int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, u32 *ctxlen); @@ -586,7 +587,8 @@ 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, void **mnt_opts) +static inline int security_add_mnt_opt(const char *option, const char *val, + int len, void **mnt_opts) { return 0; } diff --git a/security/security.c b/security/security.c index b7a5a0051807..c251278b0297 100644 --- a/security/security.c +++ b/security/security.c @@ -458,11 +458,13 @@ 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, void **mnt_opts) +int security_add_mnt_opt(const char *option, const char *val, int len, + void **mnt_opts) { - return call_int_hook(sb_parse_opts_str, 0, options, mnt_opts); + return call_int_hook(sb_add_mnt_opt, -EINVAL, + option, val, len, mnt_opts); } -EXPORT_SYMBOL(security_sb_parse_opts_str); +EXPORT_SYMBOL(security_add_mnt_opt); int security_inode_alloc(struct inode *inode) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5336d6671c5c..5bc230327bc0 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1049,40 +1049,33 @@ Einval: return -EINVAL; } -static int selinux_parse_opts_str(char *options, - void **mnt_opts) +static int selinux_add_mnt_opt(const char *option, const char *val, int len, + void **mnt_opts) { - char *p = options, *next; - int rc; - - /* Standard string-based options. */ - for (p = options; *p; p = next) { - int token, len; - char *arg = NULL; + int token = Opt_error; + int rc, i; - next = strchr(p, '|'); - if (next) { - len = next++ - p; - } else { - len = strlen(p); - next = p + len; + for (i = 0; i < ARRAY_SIZE(tokens); i++) { + if (strcmp(option, tokens[i].name) == 0) { + token = tokens[i].opt; + break; } + } - if (!len) - continue; + if (token == Opt_error) + return -EINVAL; - token = match_opt_prefix(p, len, &arg); - if (arg) - arg = kmemdup_nul(arg, p + len - arg, GFP_KERNEL); - rc = selinux_add_opt(token, arg, mnt_opts); - if (rc) { - kfree(arg); + if (token != Opt_seclabel) + val = kmemdup_nul(val, len, GFP_KERNEL); + rc = selinux_add_opt(token, val, mnt_opts); + if (unlikely(rc)) { + kfree(val); + if (*mnt_opts) { selinux_free_mnt_opts(*mnt_opts); *mnt_opts = NULL; - return rc; } } - return 0; + return rc; } static int show_sid(struct seq_file *m, u32 sid) @@ -6726,7 +6719,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_umount, selinux_umount), LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts), LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts), - LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str), + LSM_HOOK_INIT(sb_add_mnt_opt, selinux_add_mnt_opt), LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security), LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as), diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 99aec9f42be3..b607b1151e30 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4629,7 +4629,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts), LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), - LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), -- cgit v1.2.3-55-g7522 From 55c0e5bd078eba2d41d76fa25d5d5e55f1ff09ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Dec 2018 01:09:45 -0500 Subject: smack: take the guts of smack_parse_opts_str() into a new helper smack_add_opt() adds an already matched option to growing smack_mnt_options Reviewed-by: David Howells Signed-off-by: Al Viro --- security/smack/smack_lsm.c | 114 ++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 57 deletions(-) (limited to 'security/smack') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b607b1151e30..dba7bc53d86a 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -629,6 +629,54 @@ static int smack_sb_copy_data(char *orig, char *smackopts) return 0; } +static int smack_add_opt(int token, const char *s, void **mnt_opts) +{ + struct smack_mnt_opts *opts = *mnt_opts; + + if (!opts) { + opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); + if (!opts) + return -ENOMEM; + *mnt_opts = opts; + } + + if (!s) + return -ENOMEM; + + switch (token) { + case Opt_fsdefault: + if (opts->fsdefault) + goto out_opt_err; + opts->fsdefault = s; + break; + case Opt_fsfloor: + if (opts->fsfloor) + goto out_opt_err; + opts->fsfloor = s; + break; + case Opt_fshat: + if (opts->fshat) + goto out_opt_err; + opts->fshat = s; + break; + case Opt_fsroot: + if (opts->fsroot) + goto out_opt_err; + opts->fsroot = s; + break; + case Opt_fstransmute: + if (opts->fstransmute) + goto out_opt_err; + opts->fstransmute = s; + break; + } + return 0; + +out_opt_err: + pr_warn("Smack: duplicate mount options\n"); + return -EINVAL; +} + /** * smack_parse_opts_str - parse Smack specific mount options * @options: mount options string @@ -641,7 +689,6 @@ static int smack_sb_copy_data(char *orig, char *smackopts) static int smack_parse_opts_str(char *options, void **mnt_opts) { - struct smack_mnt_opts *opts = *mnt_opts; char *p; int rc = -ENOMEM; int token; @@ -651,71 +698,24 @@ static int smack_parse_opts_str(char *options, while ((p = strsep(&options, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; + const char *arg; if (!*p) continue; token = match_token(p, smk_mount_tokens, args); - if (!opts) { - opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); - if (!opts) - return -ENOMEM; - } - - switch (token) { - case Opt_fsdefault: - if (opts->fsdefault) - goto out_opt_err; - opts->fsdefault = match_strdup(&args[0]); - if (!opts->fsdefault) - goto out_err; - break; - case Opt_fsfloor: - if (opts->fsfloor) - goto out_opt_err; - opts->fsfloor = match_strdup(&args[0]); - if (!opts->fsfloor) - goto out_err; - break; - case Opt_fshat: - if (opts->fshat) - goto out_opt_err; - opts->fshat = match_strdup(&args[0]); - if (!opts->fshat) - goto out_err; - break; - case Opt_fsroot: - if (opts->fsroot) - goto out_opt_err; - opts->fsroot = match_strdup(&args[0]); - if (!opts->fsroot) - goto out_err; - break; - case Opt_fstransmute: - if (opts->fstransmute) - goto out_opt_err; - opts->fstransmute = match_strdup(&args[0]); - if (!opts->fstransmute) - goto out_err; - break; - default: - rc = -EINVAL; - pr_warn("Smack: unknown mount option\n"); - goto out_err; + arg = match_strdup(&args[0]); + rc = smack_add_opt(token, arg, mnt_opts); + if (unlikely(rc)) { + kfree(arg); + if (*mnt_opts) + smack_free_mnt_opts(*mnt_opts); + *mnt_opts = NULL; + return rc; } } - *mnt_opts = opts; return 0; - -out_opt_err: - rc = -EINVAL; - pr_warn("Smack: duplicate mount options\n"); - -out_err: - if (opts) - smack_free_mnt_opts(opts); - return rc; } static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) -- cgit v1.2.3-55-g7522 From c3300aaf95fb4e5be41e731fa6427d0d996d32ac Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Dec 2018 01:52:24 -0500 Subject: smack: get rid of match_token() same issue as with selinux... [fix by Andrei Vagin folded in] Reviewed-by: David Howells Signed-off-by: Al Viro --- security/smack/smack_lsm.c | 56 +++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 18 deletions(-) (limited to 'security/smack') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index dba7bc53d86a..d479def4d6a0 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -59,14 +59,31 @@ static LIST_HEAD(smk_ipv6_port_list); static struct kmem_cache *smack_inode_cache; int smack_enabled; -static const match_table_t smk_mount_tokens = { - {Opt_fsdefault, SMK_FSDEFAULT "%s"}, - {Opt_fsfloor, SMK_FSFLOOR "%s"}, - {Opt_fshat, SMK_FSHAT "%s"}, - {Opt_fsroot, SMK_FSROOT "%s"}, - {Opt_fstransmute, SMK_FSTRANS "%s"}, - {Opt_error, NULL}, +#define A(s) {"smack"#s, sizeof("smack"#s) - 1, Opt_##s} +static struct { + const char *name; + int len; + int opt; +} smk_mount_opts[] = { + A(fsdefault), A(fsfloor), A(fshat), A(fsroot), A(fstransmute) }; +#undef A + +static int match_opt_prefix(char *s, int l, char **arg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smk_mount_opts); i++) { + size_t len = smk_mount_opts[i].len; + if (len > l || memcmp(s, smk_mount_opts[i].name, len)) + continue; + if (len == l || s[len] != '=') + continue; + *arg = s + len + 1; + return smk_mount_opts[i].opt; + } + return Opt_error; +} #ifdef CONFIG_SECURITY_SMACK_BRINGUP static char *smk_bu_mess[] = { @@ -689,23 +706,23 @@ out_opt_err: static int smack_parse_opts_str(char *options, void **mnt_opts) { - char *p; - int rc = -ENOMEM; - int token; + char *from = options; if (!options) return 0; - while ((p = strsep(&options, ",")) != NULL) { - substring_t args[MAX_OPT_ARGS]; - const char *arg; - - if (!*p) - continue; + while (1) { + char *next = strchr(from, ','); + int token, len, rc; + char *arg = NULL; - token = match_token(p, smk_mount_tokens, args); + if (next) + len = next - from; + else + len = strlen(from); - arg = match_strdup(&args[0]); + token = match_opt_prefix(from, len, &arg); + arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL); rc = smack_add_opt(token, arg, mnt_opts); if (unlikely(rc)) { kfree(arg); @@ -714,6 +731,9 @@ static int smack_parse_opts_str(char *options, *mnt_opts = NULL; return rc; } + if (!from[len]) + break; + from += len + 1; } return 0; } -- cgit v1.2.3-55-g7522 From d2497e12e230c3f1be8ca6a0609a98c8c609fb80 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Dec 2018 01:37:06 -0500 Subject: smack: rewrite smack_sb_eat_lsm_opts() make it use smack_add_opt() and avoid separate copies - gather non-LSM options by memmove() in place Reviewed-by: David Howells Signed-off-by: Al Viro --- security/smack/smack_lsm.c | 108 ++++++++++----------------------------------- 1 file changed, 23 insertions(+), 85 deletions(-) (limited to 'security/smack') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d479def4d6a0..24a00d93d8c3 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -599,53 +599,6 @@ static void smack_free_mnt_opts(void *mnt_opts) kfree(opts); } -/** - * smack_sb_copy_data - copy mount options data for processing - * @orig: where to start - * @smackopts: mount options string - * - * Returns 0 on success or -ENOMEM on error. - * - * Copy the Smack specific mount options out of the mount - * options list. - */ -static int smack_sb_copy_data(char *orig, char *smackopts) -{ - char *cp, *commap, *otheropts, *dp; - - otheropts = (char *)get_zeroed_page(GFP_KERNEL); - if (otheropts == NULL) - return -ENOMEM; - - for (cp = orig, commap = orig; commap != NULL; cp = commap + 1) { - if (strstr(cp, SMK_FSDEFAULT) == cp) - dp = smackopts; - else if (strstr(cp, SMK_FSFLOOR) == cp) - dp = smackopts; - else if (strstr(cp, SMK_FSHAT) == cp) - dp = smackopts; - else if (strstr(cp, SMK_FSROOT) == cp) - dp = smackopts; - else if (strstr(cp, SMK_FSTRANS) == cp) - dp = smackopts; - else - dp = otheropts; - - commap = strchr(cp, ','); - if (commap != NULL) - *commap = '\0'; - - if (*dp != '\0') - strcat(dp, ","); - strcat(dp, cp); - } - - strcpy(orig, otheropts); - free_page((unsigned long)otheropts); - - return 0; -} - static int smack_add_opt(int token, const char *s, void **mnt_opts) { struct smack_mnt_opts *opts = *mnt_opts; @@ -656,7 +609,6 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts) return -ENOMEM; *mnt_opts = opts; } - if (!s) return -ENOMEM; @@ -694,22 +646,10 @@ out_opt_err: return -EINVAL; } -/** - * smack_parse_opts_str - parse Smack specific mount options - * @options: mount options string - * @opts: where to store converted mount opts - * - * Returns 0 on success or -ENOMEM on error. - * - * converts Smack specific mount options to generic security option format - */ -static int smack_parse_opts_str(char *options, - void **mnt_opts) +static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) { - char *from = options; - - if (!options) - return 0; + char *from = options, *to = options; + bool first = true; while (1) { char *next = strchr(from, ','); @@ -722,36 +662,34 @@ static int smack_parse_opts_str(char *options, len = strlen(from); token = match_opt_prefix(from, len, &arg); - arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL); - rc = smack_add_opt(token, arg, mnt_opts); - if (unlikely(rc)) { - kfree(arg); - if (*mnt_opts) - smack_free_mnt_opts(*mnt_opts); - *mnt_opts = NULL; - return rc; + if (token != Opt_error) { + arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL); + rc = smack_add_opt(token, arg, mnt_opts); + if (unlikely(rc)) { + kfree(arg); + if (*mnt_opts) + smack_free_mnt_opts(*mnt_opts); + *mnt_opts = NULL; + return rc; + } + } else { + if (!first) { // copy with preceding comma + from--; + len++; + } + if (to != from) + memmove(to, from, len); + to += len; + first = false; } if (!from[len]) break; from += len + 1; } + *to = '\0'; return 0; } -static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) -{ - char *s = (char *)get_zeroed_page(GFP_KERNEL); - int err; - - if (!s) - return -ENOMEM; - err = smack_sb_copy_data(options, s); - if (!err) - err = smack_parse_opts_str(s, mnt_opts); - free_page((unsigned long)s); - return err; -} - /** * smack_set_mnt_opts - set Smack specific mount options * @sb: the file system superblock -- cgit v1.2.3-55-g7522