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.1 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 --- security/smack/smack_lsm.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'security/smack') 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.1 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 --- security/smack/smack_lsm.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'security/smack') 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.1 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 --- security/smack/smack_lsm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'security/smack') 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.1 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 --- security/smack/smack_lsm.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'security/smack') 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.1 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.1 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 --- security/smack/smack_lsm.c | 1 - 1 file changed, 1 deletion(-) (limited to 'security/smack') 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.1 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.1 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.1 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.1