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 { | |||
| 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 | } |
