diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2018-12-14 22:44:50 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2018-12-21 11:49:28 -0500 |
commit | 169d68efb03b728588c209c682f14328eec485c0 (patch) | |
tree | 9d0f9587ee8d2863ecb558be1de2342f9aa6ee92 | |
parent | ba6418623385abf19a6c15cf0b1cfaacfdf9afc8 (diff) |
selinux: switch away from match_token()
It's not a good fit, unfortunately, and the next step will make it
even less so. Open-code what we need here.
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | security/selinux/hooks.c | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 26ec7d67e15d..8f2285cb9029 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -459,19 +459,41 @@ enum { Opt_defcontext = 3, Opt_rootcontext = 4, Opt_labelsupport = 5, - Opt_nextmntopt = 6, }; -#define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1) - -static const match_table_t tokens = { - {Opt_context, CONTEXT_STR "%s"}, - {Opt_fscontext, FSCONTEXT_STR "%s"}, - {Opt_defcontext, DEFCONTEXT_STR "%s"}, - {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, - {Opt_labelsupport, LABELSUPP_STR}, - {Opt_error, NULL}, +#define A(s, opt, has_arg) {s, sizeof(s) - 1, opt, has_arg} +static struct { + const char *name; + int len; + int opt; + bool has_arg; +} tokens[] = { + A("context", Opt_context, true), + A("fscontext", Opt_fscontext, true), + A("defcontext", Opt_defcontext, true), + A("rootcontext", Opt_rootcontext, true), + A("seclabel", Opt_labelsupport, false), }; +#undef A + +static int match_opt_prefix(char *s, int l, char **arg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tokens); i++) { + size_t len = tokens[i].len; + if (len > l || memcmp(s, tokens[i].name, len)) + continue; + if (tokens[i].has_arg) { + if (len == l || s[len] != '=') + continue; + *arg = s + len + 1; + } else if (len != l) + continue; + return tokens[i].opt; + } + return Opt_error; +} #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" @@ -988,6 +1010,9 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) { struct selinux_mnt_opts *opts = *mnt_opts; + if (token == Opt_labelsupport) /* eaten and completely ignored */ + return 0; + if (!opts) { opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); if (!opts) @@ -1021,36 +1046,39 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) return 0; Einval: pr_warn(SEL_MOUNT_FAIL_MSG); - kfree(s); return -EINVAL; } static int selinux_parse_opts_str(char *options, void **mnt_opts) { - char *p; + char *p = options, *next; + int rc; /* Standard string-based options. */ - while ((p = strsep(&options, "|")) != NULL) { - int token, rc; - substring_t args[MAX_OPT_ARGS]; - const char *arg; + for (p = options; *p; p = next) { + int token, len; + char *arg = NULL; - if (!*p) - continue; - - token = match_token(p, tokens, args); + next = strchr(p, '|'); + if (next) { + len = next++ - p; + } else { + len = strlen(p); + next = p + len; + } - if (token == Opt_labelsupport) /* eaten and completely ignored */ + if (!len) continue; - arg = match_strdup(&args[0]); + + 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 (unlikely(rc)) { + if (rc) { kfree(arg); - if (*mnt_opts) { - selinux_free_mnt_opts(*mnt_opts); - *mnt_opts = NULL; - } + selinux_free_mnt_opts(*mnt_opts); + *mnt_opts = NULL; return rc; } } |