summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-12-16 01:37:06 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2018-12-21 11:51:02 -0500
commitd2497e12e230c3f1be8ca6a0609a98c8c609fb80 (patch)
tree91156d8db61b4929b980bc4d4856803a4acb1685
parentc3300aaf95fb4e5be41e731fa6427d0d996d32ac (diff)
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 <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--security/smack/smack_lsm.c108
1 files changed, 23 insertions, 85 deletions
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