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 /security/selinux | |
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>
Diffstat (limited to 'security/selinux')
-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 { | |||
459 | Opt_defcontext = 3, | 459 | Opt_defcontext = 3, |
460 | Opt_rootcontext = 4, | 460 | Opt_rootcontext = 4, |
461 | Opt_labelsupport = 5, | 461 | Opt_labelsupport = 5, |
462 | Opt_nextmntopt = 6, | ||
463 | }; | 462 | }; |
464 | 463 | ||
465 | #define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1) | 464 | #define A(s, opt, has_arg) {s, sizeof(s) - 1, opt, has_arg} |
466 | 465 | static struct { | |
467 | static const match_table_t tokens = { | 466 | const char *name; |
468 | {Opt_context, CONTEXT_STR "%s"}, | 467 | int len; |
469 | {Opt_fscontext, FSCONTEXT_STR "%s"}, | 468 | int opt; |
470 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, | 469 | bool has_arg; |
471 | {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, | 470 | } tokens[] = { |
472 | {Opt_labelsupport, LABELSUPP_STR}, | 471 | A("context", Opt_context, true), |
473 | {Opt_error, NULL}, | 472 | A("fscontext", Opt_fscontext, true), |
473 | A("defcontext", Opt_defcontext, true), | ||
474 | A("rootcontext", Opt_rootcontext, true), | ||
475 | A("seclabel", Opt_labelsupport, false), | ||
474 | }; | 476 | }; |
477 | #undef A | ||
478 | |||
479 | static int match_opt_prefix(char *s, int l, char **arg) | ||
480 | { | ||
481 | int i; | ||
482 | |||
483 | for (i = 0; i < ARRAY_SIZE(tokens); i++) { | ||
484 | size_t len = tokens[i].len; | ||
485 | if (len > l || memcmp(s, tokens[i].name, len)) | ||
486 | continue; | ||
487 | if (tokens[i].has_arg) { | ||
488 | if (len == l || s[len] != '=') | ||
489 | continue; | ||
490 | *arg = s + len + 1; | ||
491 | } else if (len != l) | ||
492 | continue; | ||
493 | return tokens[i].opt; | ||
494 | } | ||
495 | return Opt_error; | ||
496 | } | ||
475 | 497 | ||
476 | #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" | 498 | #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" |
477 | 499 | ||
@@ -988,6 +1010,9 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) | |||
988 | { | 1010 | { |
989 | struct selinux_mnt_opts *opts = *mnt_opts; | 1011 | struct selinux_mnt_opts *opts = *mnt_opts; |
990 | 1012 | ||
1013 | if (token == Opt_labelsupport) /* eaten and completely ignored */ | ||
1014 | return 0; | ||
1015 | |||
991 | if (!opts) { | 1016 | if (!opts) { |
992 | opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); | 1017 | opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); |
993 | if (!opts) | 1018 | if (!opts) |
@@ -1021,36 +1046,39 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) | |||
1021 | return 0; | 1046 | return 0; |
1022 | Einval: | 1047 | Einval: |
1023 | pr_warn(SEL_MOUNT_FAIL_MSG); | 1048 | pr_warn(SEL_MOUNT_FAIL_MSG); |
1024 | kfree(s); | ||
1025 | return -EINVAL; | 1049 | return -EINVAL; |
1026 | } | 1050 | } |
1027 | 1051 | ||
1028 | static int selinux_parse_opts_str(char *options, | 1052 | static int selinux_parse_opts_str(char *options, |
1029 | void **mnt_opts) | 1053 | void **mnt_opts) |
1030 | { | 1054 | { |
1031 | char *p; | 1055 | char *p = options, *next; |
1056 | int rc; | ||
1032 | 1057 | ||
1033 | /* Standard string-based options. */ | 1058 | /* Standard string-based options. */ |
1034 | while ((p = strsep(&options, "|")) != NULL) { | 1059 | for (p = options; *p; p = next) { |
1035 | int token, rc; | 1060 | int token, len; |
1036 | substring_t args[MAX_OPT_ARGS]; | 1061 | char *arg = NULL; |
1037 | const char *arg; | ||
1038 | 1062 | ||
1039 | if (!*p) | 1063 | next = strchr(p, '|'); |
1040 | continue; | 1064 | if (next) { |
1041 | 1065 | len = next++ - p; | |
1042 | token = match_token(p, tokens, args); | 1066 | } else { |
1067 | len = strlen(p); | ||
1068 | next = p + len; | ||
1069 | } | ||
1043 | 1070 | ||
1044 | if (token == Opt_labelsupport) /* eaten and completely ignored */ | 1071 | if (!len) |
1045 | continue; | 1072 | continue; |
1046 | arg = match_strdup(&args[0]); | 1073 | |
1074 | token = match_opt_prefix(p, len, &arg); | ||
1075 | if (arg) | ||
1076 | arg = kmemdup_nul(arg, p + len - arg, GFP_KERNEL); | ||
1047 | rc = selinux_add_opt(token, arg, mnt_opts); | 1077 | rc = selinux_add_opt(token, arg, mnt_opts); |
1048 | if (unlikely(rc)) { | 1078 | if (rc) { |
1049 | kfree(arg); | 1079 | kfree(arg); |
1050 | if (*mnt_opts) { | 1080 | selinux_free_mnt_opts(*mnt_opts); |
1051 | selinux_free_mnt_opts(*mnt_opts); | 1081 | *mnt_opts = NULL; |
1052 | *mnt_opts = NULL; | ||
1053 | } | ||
1054 | return rc; | 1082 | return rc; |
1055 | } | 1083 | } |
1056 | } | 1084 | } |