diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 98e3639db990..3f94011c6411 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -407,7 +407,7 @@ static int tomoyo_update_manager_entry(const char *manager, return -EINVAL; e.is_domain = true; } else { - if (!tomoyo_is_correct_path(manager, 1, -1, -1)) + if (!tomoyo_is_correct_path(manager)) return -EINVAL; } e.manager = tomoyo_get_name(manager); diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index f4a8aa244af5..d1b8d791bfff 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -672,16 +672,15 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) /* Check whether the domainname is correct. */ bool tomoyo_is_correct_domain(const unsigned char *domainname); /* Check whether the token is correct. */ -bool tomoyo_is_correct_path(const char *filename, const s8 start_type, - const s8 pattern_type, const s8 end_type); +bool tomoyo_is_correct_path(const char *filename); +bool tomoyo_is_correct_word(const char *string); /* Check whether the token can be a domainname. */ bool tomoyo_is_domain_def(const unsigned char *buffer); bool tomoyo_parse_name_union(const char *filename, struct tomoyo_name_union *ptr); /* Check whether the given filename matches the given path_group. */ bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, - const struct tomoyo_path_group *group, - const bool may_use_pattern); + const struct tomoyo_path_group *group); /* Check whether the given value matches the given number_group. */ bool tomoyo_number_matches_group(const unsigned long min, const unsigned long max, diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 7b8693e29a13..50f6e7972174 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -131,11 +131,11 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(program, 1, -1, -1)) - return -EINVAL; /* No patterns allowed. */ + if (!tomoyo_is_correct_path(program)) + return -EINVAL; if (domainname) { if (!tomoyo_is_domain_def(domainname) && - tomoyo_is_correct_path(domainname, 1, -1, -1)) + tomoyo_is_correct_path(domainname)) e.is_last_name = true; else if (!tomoyo_is_correct_domain(domainname)) return -EINVAL; @@ -342,12 +342,12 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, int error = is_delete ? -ENOENT : -ENOMEM; if (!tomoyo_is_domain_def(domainname) && - tomoyo_is_correct_path(domainname, 1, -1, -1)) + tomoyo_is_correct_path(domainname)) e.is_last_name = true; else if (!tomoyo_is_correct_domain(domainname)) return -EINVAL; if (program) { - if (!tomoyo_is_correct_path(program, 1, -1, -1)) + if (!tomoyo_is_correct_path(program)) return -EINVAL; e.program = tomoyo_get_name(program); if (!e.program) @@ -533,13 +533,14 @@ static int tomoyo_update_alias_entry(const char *original_name, struct tomoyo_alias_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || - !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) - return -EINVAL; /* No patterns allowed. */ + if (!tomoyo_is_correct_path(original_name) || + !tomoyo_is_correct_path(aliased_name)) + return -EINVAL; e.original_name = tomoyo_get_name(original_name); e.aliased_name = tomoyo_get_name(aliased_name); - if (!e.original_name || !e.aliased_name) - goto out; + if (!e.original_name || !e.aliased_name || + e.original_name->is_patterned || e.aliased_name->is_patterned) + goto out; /* No patterns allowed. */ if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index cef685415df1..83fa17a1113a 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -65,23 +65,10 @@ bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr) { if (ptr->is_group) - return tomoyo_path_matches_group(name, ptr->group, 1); + return tomoyo_path_matches_group(name, ptr->group); return tomoyo_path_matches_pattern(name, ptr->filename); } -static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info - *name, - const struct tomoyo_name_union - *ptr, const bool may_use_pattern) -{ - if (ptr->is_group) - return tomoyo_path_matches_group(name, ptr->group, - may_use_pattern); - if (may_use_pattern || !ptr->filename->is_patterned) - return tomoyo_path_matches_pattern(name, ptr->filename); - return false; -} - void tomoyo_put_number_union(struct tomoyo_number_union *ptr) { if (ptr && ptr->is_group) @@ -247,7 +234,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, struct tomoyo_globally_readable_file_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(filename, 1, 0, -1)) + if (!tomoyo_is_correct_word(filename)) return -EINVAL; e.filename = tomoyo_get_name(filename); if (!e.filename) @@ -391,13 +378,14 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, const bool is_delete) { struct tomoyo_pattern_entry *ptr; - struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; + struct tomoyo_pattern_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; + if (!tomoyo_is_correct_word(pattern)) + return -EINVAL; + e.pattern = tomoyo_get_name(pattern); if (!e.pattern) return error; - if (!e.pattern->is_patterned) - goto out; if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { @@ -543,7 +531,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, struct tomoyo_no_rewrite_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) + if (!tomoyo_is_correct_word(pattern)) return -EINVAL; e.pattern = tomoyo_get_name(pattern); if (!e.pattern) @@ -690,7 +678,6 @@ static int tomoyo_update_file_acl(u8 perm, const char *filename, * @r: Pointer to "struct tomoyo_request_info". * @filename: Filename to check. * @perm: Permission. - * @may_use_pattern: True if patterned ACL is permitted. * * Returns 0 on success, -EPERM otherwise. * @@ -698,7 +685,7 @@ static int tomoyo_update_file_acl(u8 perm, const char *filename, */ static int tomoyo_path_acl(const struct tomoyo_request_info *r, const struct tomoyo_path_info *filename, - const u32 perm, const bool may_use_pattern) + const u32 perm) { struct tomoyo_domain_info *domain = r->domain; struct tomoyo_acl_info *ptr; @@ -710,8 +697,7 @@ static int tomoyo_path_acl(const struct tomoyo_request_info *r, continue; acl = container_of(ptr, struct tomoyo_path_acl, head); if (!(acl->perm & perm) || - !tomoyo_compare_name_union_pattern(filename, &acl->name, - may_use_pattern)) + !tomoyo_compare_name_union(filename, &acl->name)) continue; error = 0; break; @@ -756,7 +742,7 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r, } else BUG(); do { - error = tomoyo_path_acl(r, filename, perm, mode != 1); + error = tomoyo_path_acl(r, filename, perm); if (error && mode == 4 && !r->domain->ignore_global_allow_read && tomoyo_is_globally_readable_file(filename)) error = 0; @@ -764,7 +750,6 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r, break; tomoyo_warn_log(r, "%s %s", msg, filename->name); error = tomoyo_supervisor(r, "allow_%s %s\n", msg, - mode == 1 ? filename->name : tomoyo_file_pattern(filename)); /* * Do not retry for execute request, for alias may have @@ -1073,7 +1058,7 @@ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, next: do { - error = tomoyo_path_acl(r, filename, 1 << operation, 1); + error = tomoyo_path_acl(r, filename, 1 << operation); if (!error) break; msg = tomoyo_path2keyword(operation); diff --git a/security/tomoyo/number_group.c b/security/tomoyo/number_group.c index c49792e09e81..8d6ef8f006ff 100644 --- a/security/tomoyo/number_group.c +++ b/security/tomoyo/number_group.c @@ -24,8 +24,7 @@ struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name) struct tomoyo_number_group *group = NULL; const struct tomoyo_path_info *saved_group_name; int error = -ENOMEM; - if (!tomoyo_is_correct_path(group_name, 0, 0, 0) || - !group_name[0]) + if (!tomoyo_is_correct_word(group_name)) return NULL; saved_group_name = tomoyo_get_name(group_name); if (!saved_group_name) diff --git a/security/tomoyo/path_group.c b/security/tomoyo/path_group.c index 636025e26b06..07e4f782367b 100644 --- a/security/tomoyo/path_group.c +++ b/security/tomoyo/path_group.c @@ -22,8 +22,7 @@ struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name) struct tomoyo_path_group *group = NULL; const struct tomoyo_path_info *saved_group_name; int error = -ENOMEM; - if (!tomoyo_is_correct_path(group_name, 0, 0, 0) || - !group_name[0]) + if (!tomoyo_is_correct_word(group_name)) return NULL; saved_group_name = tomoyo_get_name(group_name); if (!saved_group_name) @@ -141,29 +140,21 @@ bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head) * * @pathname: The name of pathname. * @group: Pointer to "struct tomoyo_path_group". - * @may_use_pattern: True if wild card is permitted. * * Returns true if @pathname matches pathnames in @group, false otherwise. * * Caller holds tomoyo_read_lock(). */ bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, - const struct tomoyo_path_group *group, - const bool may_use_pattern) + const struct tomoyo_path_group *group) { struct tomoyo_path_group_member *member; bool matched = false; list_for_each_entry_rcu(member, &group->member_list, list) { if (member->is_deleted) continue; - if (!member->member_name->is_patterned) { - if (tomoyo_pathcmp(pathname, member->member_name)) - continue; - } else if (may_use_pattern) { - if (!tomoyo_path_matches_pattern(pathname, - member->member_name)) - continue; - } else + if (!tomoyo_path_matches_pattern(pathname, + member->member_name)) continue; matched = true; break; diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 7b023f5e1314..592b76a2bce8 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -89,7 +89,7 @@ void tomoyo_print_ulong(char *buffer, const int buffer_len, bool tomoyo_parse_name_union(const char *filename, struct tomoyo_name_union *ptr) { - if (!tomoyo_is_correct_path(filename, 0, 0, 0)) + if (!tomoyo_is_correct_word(filename)) return false; if (filename[0] == '@') { ptr->group = tomoyo_get_path_group(filename + 1); @@ -115,7 +115,7 @@ bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) unsigned long v; memset(num, 0, sizeof(*num)); if (data[0] == '@') { - if (!tomoyo_is_correct_path(data, 0, 0, 0)) + if (!tomoyo_is_correct_word(data)) return false; num->group = tomoyo_get_number_group(data + 1); num->is_group = true; @@ -265,54 +265,29 @@ bool tomoyo_tokenize(char *buffer, char *w[], size_t size) } /** - * tomoyo_is_correct_path - Validate a pathname. + * tomoyo_is_correct_word2 - Validate a string. * - * @filename: The pathname to check. - * @start_type: Should the pathname start with '/'? - * 1 = must / -1 = must not / 0 = don't care - * @pattern_type: Can the pathname contain a wildcard? - * 1 = must / -1 = must not / 0 = don't care - * @end_type: Should the pathname end with '/'? - * 1 = must / -1 = must not / 0 = don't care + * @string: The string to check. May be non-'\0'-terminated. + * @len: Length of @string. * - * Check whether the given filename follows the naming rules. - * Returns true if @filename follows the naming rules, false otherwise. + * Check whether the given string follows the naming rules. + * Returns true if @string follows the naming rules, false otherwise. */ -bool tomoyo_is_correct_path(const char *filename, const s8 start_type, - const s8 pattern_type, const s8 end_type) +static bool tomoyo_is_correct_word2(const char *string, size_t len) { - const char *const start = filename; + const char *const start = string; bool in_repetition = false; - bool contains_pattern = false; unsigned char c; unsigned char d; unsigned char e; - - if (!filename) + if (!len) goto out; - c = *filename; - if (start_type == 1) { /* Must start with '/' */ - if (c != '/') - goto out; - } else if (start_type == -1) { /* Must not start with '/' */ - if (c == '/') - goto out; - } - if (c) - c = *(filename + strlen(filename) - 1); - if (end_type == 1) { /* Must end with '/' */ - if (c != '/') - goto out; - } else if (end_type == -1) { /* Must not end with '/' */ - if (c == '/') - goto out; - } - while (1) { - c = *filename++; - if (!c) - break; + while (len--) { + c = *string++; if (c == '\\') { - c = *filename++; + if (!len--) + goto out; + c = *string++; switch (c) { case '\\': /* "\\" */ continue; @@ -326,21 +301,14 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, case 'a': /* "\a" */ case 'A': /* "\A" */ case '-': /* "\-" */ - if (pattern_type == -1) - break; /* Must not contain pattern */ - contains_pattern = true; continue; case '{': /* "/\{" */ - if (filename - 3 < start || - *(filename - 3) != '/') + if (string - 3 < start || *(string - 3) != '/') break; - if (pattern_type == -1) - break; /* Must not contain pattern */ - contains_pattern = true; in_repetition = true; continue; case '}': /* "\}/" */ - if (*filename != '/') + if (*string != '/') break; if (!in_repetition) break; @@ -350,11 +318,11 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, case '1': case '2': case '3': - d = *filename++; - if (d < '0' || d > '7') + if (!len-- || !len--) break; - e = *filename++; - if (e < '0' || e > '7') + d = *string++; + e = *string++; + if (d < '0' || d > '7' || e < '0' || e > '7') break; c = tomoyo_make_byte(c, d, e); if (tomoyo_is_invalid(c)) @@ -367,10 +335,6 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, goto out; } } - if (pattern_type == 1) { /* Must contain pattern */ - if (!contains_pattern) - goto out; - } if (in_repetition) goto out; return true; @@ -378,59 +342,59 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, return false; } +/** + * tomoyo_is_correct_word - Validate a string. + * + * @string: The string to check. + * + * Check whether the given string follows the naming rules. + * Returns true if @string follows the naming rules, false otherwise. + */ +bool tomoyo_is_correct_word(const char *string) +{ + return tomoyo_is_correct_word2(string, strlen(string)); +} + +/** + * tomoyo_is_correct_path - Validate a pathname. + * + * @filename: The pathname to check. + * + * Check whether the given pathname follows the naming rules. + * Returns true if @filename follows the naming rules, false otherwise. + */ +bool tomoyo_is_correct_path(const char *filename) +{ + return *filename == '/' && tomoyo_is_correct_word(filename); +} + /** * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. * - * @domainname: The domainname to check. + * @domainname: The domainname to check. * * Returns true if @domainname follows the naming rules, false otherwise. */ bool tomoyo_is_correct_domain(const unsigned char *domainname) { - unsigned char c; - unsigned char d; - unsigned char e; - if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN)) goto out; domainname += TOMOYO_ROOT_NAME_LEN; if (!*domainname) return true; - do { - if (*domainname++ != ' ') + if (*domainname++ != ' ') + goto out; + while (1) { + const unsigned char *cp = strchr(domainname, ' '); + if (!cp) + break; + if (*domainname != '/' || + !tomoyo_is_correct_word2(domainname, cp - domainname - 1)) goto out; - if (*domainname++ != '/') - goto out; - while ((c = *domainname) != '\0' && c != ' ') { - domainname++; - if (c == '\\') { - c = *domainname++; - switch ((c)) { - case '\\': /* "\\" */ - continue; - case '0': /* "\ooo" */ - case '1': - case '2': - case '3': - d = *domainname++; - if (d < '0' || d > '7') - break; - e = *domainname++; - if (e < '0' || e > '7') - break; - c = tomoyo_make_byte(c, d, e); - if (tomoyo_is_invalid(c)) - /* pattern is not \000 */ - continue; - } - goto out; - } else if (tomoyo_is_invalid(c)) { - goto out; - } - } - } while (*domainname); - return true; + domainname = cp + 1; + } + return tomoyo_is_correct_path(domainname); out: return false; }