From a238cf5b89ed5285be8de56335665d023972f7d5 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 26 Jun 2011 23:17:10 +0900 Subject: [PATCH] TOMOYO: Use struct for passing ACL line. Use structure for passing ACL line, in preparation for supporting policy namespace and conditional parameters. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 77 +++++++------ security/tomoyo/common.h | 32 ++++-- security/tomoyo/domain.c | 146 ++++++++++-------------- security/tomoyo/file.c | 237 +++++++++++++++++++++------------------ security/tomoyo/group.c | 33 +++--- security/tomoyo/memory.c | 20 ++-- security/tomoyo/mount.c | 53 --------- security/tomoyo/util.c | 120 +++++++++++--------- 8 files changed, 347 insertions(+), 371 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 2e6792ded357..2cfadafd02f5 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -611,8 +611,11 @@ static int tomoyo_update_manager_entry(const char *manager, const bool is_delete) { struct tomoyo_manager e = { }; - int error; - + struct tomoyo_acl_param param = { + .is_delete = is_delete, + .list = &tomoyo_policy_list[TOMOYO_ID_MANAGER], + }; + int error = is_delete ? -ENOENT : -ENOMEM; if (tomoyo_domain_def(manager)) { if (!tomoyo_correct_domain(manager)) return -EINVAL; @@ -622,12 +625,11 @@ static int tomoyo_update_manager_entry(const char *manager, return -EINVAL; } e.manager = tomoyo_get_name(manager); - if (!e.manager) - return -ENOMEM; - error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, - &tomoyo_policy_list[TOMOYO_ID_MANAGER], - tomoyo_same_manager); - tomoyo_put_name(e.manager); + if (e.manager) { + error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, + tomoyo_same_manager); + tomoyo_put_name(e.manager); + } return error; } @@ -821,18 +823,36 @@ static int tomoyo_delete_domain(char *domainname) /** * tomoyo_write_domain2 - Write domain policy. * - * @head: Pointer to "struct tomoyo_io_buffer". + * @list: Pointer to "struct list_head". + * @data: Policy to be interpreted. + * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain, +static int tomoyo_write_domain2(struct list_head *list, char *data, const bool is_delete) { - if (tomoyo_str_starts(&data, "allow_mount ")) - return tomoyo_write_mount(data, domain, is_delete); - return tomoyo_write_file(data, domain, is_delete); + struct tomoyo_acl_param param = { + .list = list, + .data = data, + .is_delete = is_delete, + }; + static const struct { + const char *keyword; + int (*write) (struct tomoyo_acl_param *); + } tomoyo_callback[1] = { + { "file ", tomoyo_write_file }, + }; + u8 i; + for (i = 0; i < 1; i++) { + if (!tomoyo_str_starts(¶m.data, + tomoyo_callback[i].keyword)) + continue; + return tomoyo_callback[i].write(¶m); + } + return -EINVAL; } /** @@ -889,7 +909,7 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) domain->transition_failed = !is_delete; return 0; } - return tomoyo_write_domain2(data, domain, is_delete); + return tomoyo_write_domain2(&domain->acl_info_list, data, is_delete); } /** @@ -1213,26 +1233,19 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { */ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) { - char *data = head->write_buf; - bool is_delete = tomoyo_str_starts(&data, "delete "); - u8 i; - static const struct { - const char *keyword; - int (*write) (char *, const bool); - } tomoyo_callback[1] = { - { "aggregator ", tomoyo_write_aggregator }, + struct tomoyo_acl_param param = { + .data = head->write_buf, }; - + u8 i; + param.is_delete = tomoyo_str_starts(¶m.data, "delete "); + if (tomoyo_str_starts(¶m.data, "aggregator ")) + return tomoyo_write_aggregator(¶m); for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) - if (tomoyo_str_starts(&data, tomoyo_transition_type[i])) - return tomoyo_write_transition_control(data, is_delete, - i); - for (i = 0; i < 1; i++) - if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword)) - return tomoyo_callback[i].write(data, is_delete); + if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i])) + return tomoyo_write_transition_control(¶m, i); for (i = 0; i < TOMOYO_MAX_GROUP; i++) - if (tomoyo_str_starts(&data, tomoyo_group_name[i])) - return tomoyo_write_group(data, is_delete, i); + if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) + return tomoyo_write_group(¶m, i); return -EINVAL; } @@ -1490,7 +1503,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) vsnprintf(buffer, len - 1, fmt, args); va_end(args); tomoyo_normalize_line(buffer); - tomoyo_write_domain2(buffer, r->domain, false); + tomoyo_write_domain2(&r->domain->acl_info_list, buffer, false); kfree(buffer); /* fall through */ case TOMOYO_CONFIG_PERMISSIVE: diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 7aa55eef67bd..6f9711ff73c1 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -397,6 +397,13 @@ struct tomoyo_mount_acl { struct tomoyo_number_union flags; }; +/* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */ +struct tomoyo_acl_param { + char *data; + struct list_head *list; + bool is_delete; +}; + #define TOMOYO_MAX_IO_READ_QUEUE 32 /* @@ -521,7 +528,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname); bool tomoyo_correct_path(const char *filename); bool tomoyo_correct_word(const char *string); bool tomoyo_domain_def(const unsigned char *buffer); -bool tomoyo_parse_name_union(const char *filename, +bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, struct tomoyo_name_union *ptr); const struct tomoyo_path_info * tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, @@ -531,7 +538,8 @@ bool tomoyo_number_matches_group(const unsigned long min, const struct tomoyo_group *group); bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, const struct tomoyo_path_info *pattern); -bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num); +bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, + struct tomoyo_number_union *ptr); bool tomoyo_tokenize(char *buffer, char *w[], size_t size); bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); int tomoyo_init_request_info(struct tomoyo_request_info *r, @@ -540,21 +548,19 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, int tomoyo_mount_permission(char *dev_name, struct path *path, const char *type, unsigned long flags, void *data_page); -int tomoyo_write_aggregator(char *data, const bool is_delete); -int tomoyo_write_transition_control(char *data, const bool is_delete, +int tomoyo_write_aggregator(struct tomoyo_acl_param *param); +int tomoyo_write_transition_control(struct tomoyo_acl_param *param, const u8 type); -int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain, - const bool is_delete); -int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain, - const bool is_delete); -int tomoyo_write_group(char *data, const bool is_delete, const u8 type); +int tomoyo_write_file(struct tomoyo_acl_param *param); +int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type); int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, const u8 profile); struct tomoyo_profile *tomoyo_profile(const u8 profile); -struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type); +struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, + const u8 idx); unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, const u8 index); void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); @@ -587,7 +593,7 @@ void tomoyo_put_name_union(struct tomoyo_name_union *ptr); void tomoyo_run_gc(void); void tomoyo_memory_free(void *ptr); int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, - bool is_delete, struct tomoyo_domain_info *domain, + struct tomoyo_acl_param *param, bool (*check_duplicate) (const struct tomoyo_acl_info *, const struct tomoyo_acl_info @@ -596,7 +602,7 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, struct tomoyo_acl_info *, const bool)); int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, - bool is_delete, struct list_head *list, + struct tomoyo_acl_param *param, bool (*check_duplicate) (const struct tomoyo_acl_head *, const struct tomoyo_acl_head @@ -604,6 +610,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, void tomoyo_check_acl(struct tomoyo_request_info *r, bool (*check_entry) (struct tomoyo_request_info *, const struct tomoyo_acl_info *)); +char *tomoyo_read_token(struct tomoyo_acl_param *param); +bool tomoyo_permstr(const char *string, const char *keyword); /********** External variable definitions. **********/ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 43977083254b..d818717954f8 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -20,8 +20,7 @@ struct tomoyo_domain_info tomoyo_kernel_domain; * * @new_entry: Pointer to "struct tomoyo_acl_info". * @size: Size of @new_entry in bytes. - * @is_delete: True if it is a delete request. - * @list: Pointer to "struct list_head". + * @param: Pointer to "struct tomoyo_acl_param". * @check_duplicate: Callback function to find duplicated entry. * * Returns 0 on success, negative value otherwise. @@ -29,25 +28,26 @@ struct tomoyo_domain_info tomoyo_kernel_domain; * Caller holds tomoyo_read_lock(). */ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, - bool is_delete, struct list_head *list, + struct tomoyo_acl_param *param, bool (*check_duplicate) (const struct tomoyo_acl_head *, const struct tomoyo_acl_head *)) { - int error = is_delete ? -ENOENT : -ENOMEM; + int error = param->is_delete ? -ENOENT : -ENOMEM; struct tomoyo_acl_head *entry; + struct list_head *list = param->list; if (mutex_lock_interruptible(&tomoyo_policy_lock)) return -ENOMEM; list_for_each_entry_rcu(entry, list, list) { if (!check_duplicate(entry, new_entry)) continue; - entry->is_deleted = is_delete; + entry->is_deleted = param->is_delete; error = 0; break; } - if (error && !is_delete) { + if (error && !param->is_delete) { entry = tomoyo_commit_ok(new_entry, size); if (entry) { list_add_tail_rcu(&entry->list, list); @@ -77,8 +77,7 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, * * @new_entry: Pointer to "struct tomoyo_acl_info". * @size: Size of @new_entry in bytes. - * @is_delete: True if it is a delete request. - * @domain: Pointer to "struct tomoyo_domain_info". + * @param: Pointer to "struct tomoyo_acl_param". * @check_duplicate: Callback function to find duplicated entry. * @merge_duplicate: Callback function to merge duplicated entry. * @@ -87,7 +86,7 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, * Caller holds tomoyo_read_lock(). */ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, - bool is_delete, struct tomoyo_domain_info *domain, + struct tomoyo_acl_param *param, bool (*check_duplicate) (const struct tomoyo_acl_info *, const struct tomoyo_acl_info @@ -96,12 +95,14 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, struct tomoyo_acl_info *, const bool)) { + const bool is_delete = param->is_delete; int error = is_delete ? -ENOENT : -ENOMEM; struct tomoyo_acl_info *entry; + struct list_head * const list = param->list; if (mutex_lock_interruptible(&tomoyo_policy_lock)) return error; - list_for_each_entry_rcu(entry, &domain->acl_info_list, list) { + list_for_each_entry_rcu(entry, list, list) { if (!tomoyo_same_acl_head(entry, new_entry) || !check_duplicate(entry, new_entry)) continue; @@ -116,7 +117,7 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, if (error && !is_delete) { entry = tomoyo_commit_ok(new_entry, size); if (entry) { - list_add_tail_rcu(&entry->list, &domain->acl_info_list); + list_add_tail_rcu(&entry->list, list); error = 0; } } @@ -163,6 +164,14 @@ static const char *tomoyo_last_word(const char *name) return name; } +/** + * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry. + * + * @a: Pointer to "struct tomoyo_acl_head". + * @b: Pointer to "struct tomoyo_acl_head". + * + * Returns true if @a == @b, false otherwise. + */ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, const struct tomoyo_acl_head *b) { @@ -178,22 +187,28 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, } /** - * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list. + * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. * - * @domainname: The name of domain. Maybe NULL. - * @program: The name of program. Maybe NULL. - * @type: Type of transition. - * @is_delete: True if it is a delete request. + * @param: Pointer to "struct tomoyo_acl_param". + * @type: Type of this entry. * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_update_transition_control_entry(const char *domainname, - const char *program, - const u8 type, - const bool is_delete) +int tomoyo_write_transition_control(struct tomoyo_acl_param *param, + const u8 type) { struct tomoyo_transition_control e = { .type = type }; - int error = is_delete ? -ENOENT : -ENOMEM; + int error = param->is_delete ? -ENOENT : -ENOMEM; + char *program = param->data; + char *domainname = strstr(program, " from "); + if (domainname) { + *domainname = '\0'; + domainname += 6; + } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || + type == TOMOYO_TRANSITION_CONTROL_KEEP) { + domainname = program; + program = NULL; + } if (program) { if (!tomoyo_correct_path(program)) return -EINVAL; @@ -211,41 +226,15 @@ static int tomoyo_update_transition_control_entry(const char *domainname, if (!e.domainname) goto out; } - error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, - &tomoyo_policy_list - [TOMOYO_ID_TRANSITION_CONTROL], + param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL]; + error = tomoyo_update_policy(&e.head, sizeof(e), param, tomoyo_same_transition_control); - out: +out: tomoyo_put_name(e.domainname); tomoyo_put_name(e.program); return error; } -/** - * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. - * - * @data: String to parse. - * @is_delete: True if it is a delete request. - * @type: Type of this entry. - * - * Returns 0 on success, negative value otherwise. - */ -int tomoyo_write_transition_control(char *data, const bool is_delete, - const u8 type) -{ - char *domainname = strstr(data, " from "); - if (domainname) { - *domainname = '\0'; - domainname += 6; - } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || - type == TOMOYO_TRANSITION_CONTROL_KEEP) { - domainname = data; - data = NULL; - } - return tomoyo_update_transition_control_entry(domainname, data, type, - is_delete); -} - /** * tomoyo_transition_type - Get domain transition type. * @@ -303,34 +292,41 @@ static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, return type; } +/** + * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry. + * + * @a: Pointer to "struct tomoyo_acl_head". + * @b: Pointer to "struct tomoyo_acl_head". + * + * Returns true if @a == @b, false otherwise. + */ static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, const struct tomoyo_acl_head *b) { - const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head); - const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head); + const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), + head); + const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), + head); return p1->original_name == p2->original_name && p1->aggregated_name == p2->aggregated_name; } /** - * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list. + * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. * - * @original_name: The original program's name. - * @aggregated_name: The program name to use. - * @is_delete: True if it is a delete request. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_aggregator_entry(const char *original_name, - const char *aggregated_name, - const bool is_delete) +int tomoyo_write_aggregator(struct tomoyo_acl_param *param) { struct tomoyo_aggregator e = { }; - int error = is_delete ? -ENOENT : -ENOMEM; - - if (!tomoyo_correct_path(original_name) || + int error = param->is_delete ? -ENOENT : -ENOMEM; + const char *original_name = tomoyo_read_token(param); + const char *aggregated_name = tomoyo_read_token(param); + if (!tomoyo_correct_word(original_name) || !tomoyo_correct_path(aggregated_name)) return -EINVAL; e.original_name = tomoyo_get_name(original_name); @@ -338,35 +334,15 @@ static int tomoyo_update_aggregator_entry(const char *original_name, if (!e.original_name || !e.aggregated_name || e.aggregated_name->is_patterned) /* No patterns allowed. */ goto out; - error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, - &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR], + param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]; + error = tomoyo_update_policy(&e.head, sizeof(e), param, tomoyo_same_aggregator); - out: +out: tomoyo_put_name(e.original_name); tomoyo_put_name(e.aggregated_name); return error; } -/** - * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. - * - * @data: String to parse. - * @is_delete: True if it is a delete request. - * - * Returns 0 on success, negative value otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -int tomoyo_write_aggregator(char *data, const bool is_delete) -{ - char *cp = strchr(data, ' '); - - if (!cp) - return -EINVAL; - *cp++ = '\0'; - return tomoyo_update_aggregator_entry(data, cp, is_delete); -} - /** * tomoyo_assign_domain - Create a domain. * diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 4259e0a136d8..e60745f9f31e 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -428,29 +428,27 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, /** * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. * - * @type: Type of operation. - * @filename: Filename. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_path_acl(const u8 type, const char *filename, - struct tomoyo_domain_info * const domain, - const bool is_delete) +static int tomoyo_update_path_acl(const u16 perm, + struct tomoyo_acl_param *param) { struct tomoyo_path_acl e = { .head.type = TOMOYO_TYPE_PATH_ACL, - .perm = 1 << type + .perm = perm }; int error; - if (!tomoyo_parse_name_union(filename, &e.name)) - return -EINVAL; - error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, - tomoyo_same_path_acl, - tomoyo_merge_path_acl); + if (!tomoyo_parse_name_union(param, &e.name)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_path_acl, + tomoyo_merge_path_acl); tomoyo_put_name_union(&e.name); return error; } @@ -503,37 +501,30 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, /** * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. * - * @type: Type of operation. - * @filename: Filename. - * @mode: Create mode. - * @major: Device major number. - * @minor: Device minor number. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, - char *mode, char *major, char *minor, - struct tomoyo_domain_info * const domain, - const bool is_delete) +static int tomoyo_update_mkdev_acl(const u8 perm, + struct tomoyo_acl_param *param) { struct tomoyo_mkdev_acl e = { .head.type = TOMOYO_TYPE_MKDEV_ACL, - .perm = 1 << type + .perm = perm }; - int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_parse_name_union(filename, &e.name) || - !tomoyo_parse_number_union(mode, &e.mode) || - !tomoyo_parse_number_union(major, &e.major) || - !tomoyo_parse_number_union(minor, &e.minor)) - goto out; - error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, - tomoyo_same_mkdev_acl, - tomoyo_merge_mkdev_acl); - out: + int error; + if (!tomoyo_parse_name_union(param, &e.name) || + !tomoyo_parse_number_union(param, &e.mode) || + !tomoyo_parse_number_union(param, &e.major) || + !tomoyo_parse_number_union(param, &e.minor)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_mkdev_acl, + tomoyo_merge_mkdev_acl); tomoyo_put_name_union(&e.name); tomoyo_put_number_union(&e.mode); tomoyo_put_number_union(&e.major); @@ -586,33 +577,28 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, /** * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. * - * @type: Type of operation. - * @filename1: First filename. - * @filename2: Second filename. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_path2_acl(const u8 type, const char *filename1, - const char *filename2, - struct tomoyo_domain_info * const domain, - const bool is_delete) +static int tomoyo_update_path2_acl(const u8 perm, + struct tomoyo_acl_param *param) { struct tomoyo_path2_acl e = { .head.type = TOMOYO_TYPE_PATH2_ACL, - .perm = 1 << type + .perm = perm }; - int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_parse_name_union(filename1, &e.name1) || - !tomoyo_parse_name_union(filename2, &e.name2)) - goto out; - error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, - tomoyo_same_path2_acl, - tomoyo_merge_path2_acl); - out: + int error; + if (!tomoyo_parse_name_union(param, &e.name1) || + !tomoyo_parse_name_union(param, &e.name2)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_path2_acl, + tomoyo_merge_path2_acl); tomoyo_put_name_union(&e.name1); tomoyo_put_name_union(&e.name2); return error; @@ -701,32 +687,26 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, /** * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. * - * @type: Type of operation. - * @filename: Filename. - * @number: Number. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_update_path_number_acl(const u8 type, const char *filename, - char *number, - struct tomoyo_domain_info * const - domain, const bool is_delete) +static int tomoyo_update_path_number_acl(const u8 perm, + struct tomoyo_acl_param *param) { struct tomoyo_path_number_acl e = { .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, - .perm = 1 << type + .perm = perm }; - int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_parse_name_union(filename, &e.name)) - return -EINVAL; - if (!tomoyo_parse_number_union(number, &e.number)) - goto out; - error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, - tomoyo_same_path_number_acl, - tomoyo_merge_path_number_acl); - out: + int error; + if (!tomoyo_parse_name_union(param, &e.name) || + !tomoyo_parse_number_union(param, &e.number)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_path_number_acl, + tomoyo_merge_path_number_acl); tomoyo_put_name_union(&e.name); tomoyo_put_number_union(&e.number); return error; @@ -962,54 +942,89 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, return error; } +/** + * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * + * Returns true if @a == @b, false otherwise. + */ +static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) +{ + const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); + return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && + tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && + tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && + tomoyo_same_number_union(&p1->flags, &p2->flags); +} + +/** + * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) +{ + struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; + int error; + if (!tomoyo_parse_name_union(param, &e.dev_name) || + !tomoyo_parse_name_union(param, &e.dir_name) || + !tomoyo_parse_name_union(param, &e.fs_type) || + !tomoyo_parse_number_union(param, &e.flags)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_mount_acl, NULL); + tomoyo_put_name_union(&e.dev_name); + tomoyo_put_name_union(&e.dir_name); + tomoyo_put_name_union(&e.fs_type); + tomoyo_put_number_union(&e.flags); + return error; +} + /** * tomoyo_write_file - Update file related list. * - * @data: String to parse. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ -int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain, - const bool is_delete) +int tomoyo_write_file(struct tomoyo_acl_param *param) { - char *w[5]; + u16 perm = 0; u8 type; - if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) - return -EINVAL; - if (strncmp(w[0], "allow_", 6)) - goto out; - w[0] += 6; - for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { - if (strcmp(w[0], tomoyo_path_keyword[type])) - continue; - return tomoyo_update_path_acl(type, w[1], domain, is_delete); - } - if (!w[2][0]) - goto out; - for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { - if (strcmp(w[0], tomoyo_path2_keyword[type])) - continue; - return tomoyo_update_path2_acl(type, w[1], w[2], domain, - is_delete); - } - for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { - if (strcmp(w[0], tomoyo_path_number_keyword[type])) - continue; - return tomoyo_update_path_number_acl(type, w[1], w[2], domain, - is_delete); - } - if (!w[3][0] || !w[4][0]) - goto out; - for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { - if (strcmp(w[0], tomoyo_mkdev_keyword[type])) - continue; - return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], - w[4], domain, is_delete); - } - out: + const char *operation = tomoyo_read_token(param); + for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) + if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) + perm |= 1 << type; + if (perm) + return tomoyo_update_path_acl(perm, param); + for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) + if (tomoyo_permstr(operation, tomoyo_path2_keyword[type])) + perm |= 1 << type; + if (perm) + return tomoyo_update_path2_acl(perm, param); + for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) + if (tomoyo_permstr(operation, + tomoyo_path_number_keyword[type])) + perm |= 1 << type; + if (perm) + return tomoyo_update_path_number_acl(perm, param); + for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) + if (tomoyo_permstr(operation, tomoyo_mkdev_keyword[type])) + perm |= 1 << type; + if (perm) + return tomoyo_update_mkdev_acl(perm, param); + if (tomoyo_permstr(operation, "mount")) + return tomoyo_update_mount_acl(param); return -EINVAL; } diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c index e94352ce723f..2e5b7bc73264 100644 --- a/security/tomoyo/group.c +++ b/security/tomoyo/group.c @@ -28,48 +28,41 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a, /** * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list. * - * @data: String to parse. - * @is_delete: True if it is a delete request. + * @param: Pointer to "struct tomoyo_acl_param". * @type: Type of this group. * * Returns 0 on success, negative value otherwise. */ -int tomoyo_write_group(char *data, const bool is_delete, const u8 type) +int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type) { - struct tomoyo_group *group; - struct list_head *member; - char *w[2]; + struct tomoyo_group *group = tomoyo_get_group(param, type); int error = -EINVAL; - if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) - return -EINVAL; - group = tomoyo_get_group(w[0], type); if (!group) return -ENOMEM; - member = &group->member_list; + param->list = &group->member_list; if (type == TOMOYO_PATH_GROUP) { struct tomoyo_path_group e = { }; - e.member_name = tomoyo_get_name(w[1]); + e.member_name = tomoyo_get_name(tomoyo_read_token(param)); if (!e.member_name) { error = -ENOMEM; goto out; } - error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, - member, tomoyo_same_path_group); + error = tomoyo_update_policy(&e.head, sizeof(e), param, + tomoyo_same_path_group); tomoyo_put_name(e.member_name); } else if (type == TOMOYO_NUMBER_GROUP) { struct tomoyo_number_group e = { }; - if (w[1][0] == '@' - || !tomoyo_parse_number_union(w[1], &e.number) - || e.number.values[0] > e.number.values[1]) + if (param->data[0] == '@' || + !tomoyo_parse_number_union(param, &e.number)) goto out; - error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, - member, tomoyo_same_number_group); + error = tomoyo_update_policy(&e.head, sizeof(e), param, + tomoyo_same_number_group); /* * tomoyo_put_number_union() is not needed because - * w[1][0] != '@'. + * param->data[0] != '@'. */ } - out: +out: tomoyo_put_group(group); return error; } diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index dfef0cb268dc..839b8ebc6fe6 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c @@ -93,15 +93,18 @@ void tomoyo_memory_free(void *ptr) /** * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group". * - * @group_name: The name of address group. - * @idx: Index number. + * @param: Pointer to "struct tomoyo_acl_param". + * @idx: Index number. * * Returns pointer to "struct tomoyo_group" on success, NULL otherwise. */ -struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx) +struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param, + const u8 idx) { struct tomoyo_group e = { }; struct tomoyo_group *group = NULL; + struct list_head *list; + const char *group_name = tomoyo_read_token(param); bool found = false; if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP) return NULL; @@ -110,7 +113,8 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx) return NULL; if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; - list_for_each_entry(group, &tomoyo_group_list[idx], head.list) { + list = &tomoyo_group_list[idx]; + list_for_each_entry(group, list, head.list) { if (e.group_name != group->group_name) continue; atomic_inc(&group->head.users); @@ -122,14 +126,13 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx) if (entry) { INIT_LIST_HEAD(&entry->member_list); atomic_set(&entry->head.users, 1); - list_add_tail_rcu(&entry->head.list, - &tomoyo_group_list[idx]); + list_add_tail_rcu(&entry->head.list, list); group = entry; found = true; } } mutex_unlock(&tomoyo_policy_lock); - out: +out: tomoyo_put_name(e.group_name); return found ? group : NULL; } @@ -210,6 +213,8 @@ void __init tomoyo_mm_init(void) idx = tomoyo_read_lock(); if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) panic("Can't register tomoyo_kernel_domain"); +#if 0 + /* Will be replaced with tomoyo_load_builtin_policy(). */ { /* Load built-in policy. */ tomoyo_write_transition_control("/sbin/hotplug", false, @@ -217,6 +222,7 @@ void __init tomoyo_mm_init(void) tomoyo_write_transition_control("/sbin/modprobe", false, TOMOYO_TRANSITION_CONTROL_INITIALIZE); } +#endif tomoyo_read_unlock(idx); } diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 7649dbc6a56b..1e610f96c99d 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -243,56 +243,3 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, tomoyo_read_unlock(idx); return error; } - -/** - * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. - * - * @a: Pointer to "struct tomoyo_acl_info". - * @b: Pointer to "struct tomoyo_acl_info". - * - * Returns true if @a == @b, false otherwise. - */ -static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, - const struct tomoyo_acl_info *b) -{ - const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); - const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); - return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && - tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && - tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && - tomoyo_same_number_union(&p1->flags, &p2->flags); -} - -/** - * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list. - * - * @data: String to parse. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. - * - * Returns 0 on success, negative value otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain, - const bool is_delete) -{ - struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; - int error = is_delete ? -ENOENT : -ENOMEM; - char *w[4]; - if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0]) - return -EINVAL; - if (!tomoyo_parse_name_union(w[0], &e.dev_name) || - !tomoyo_parse_name_union(w[1], &e.dir_name) || - !tomoyo_parse_name_union(w[2], &e.fs_type) || - !tomoyo_parse_number_union(w[3], &e.flags)) - goto out; - error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, - tomoyo_same_mount_acl, NULL); - out: - tomoyo_put_name_union(&e.dev_name); - tomoyo_put_name_union(&e.dir_name); - tomoyo_put_name_union(&e.fs_type); - tomoyo_put_number_union(&e.flags); - return error; -} diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index abb177c2d7c2..72cd2b97cae8 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -15,6 +15,46 @@ DEFINE_MUTEX(tomoyo_policy_lock); /* Has /sbin/init started? */ bool tomoyo_policy_loaded; +/** + * tomoyo_permstr - Find permission keywords. + * + * @string: String representation for permissions in foo/bar/buz format. + * @keyword: Keyword to find from @string/ + * + * Returns ture if @keyword was found in @string, false otherwise. + * + * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2. + */ +bool tomoyo_permstr(const char *string, const char *keyword) +{ + const char *cp = strstr(string, keyword); + if (cp) + return cp == string || *(cp - 1) == '/'; + return false; +} + +/** + * tomoyo_read_token - Read a word from a line. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns a word on success, "" otherwise. + * + * To allow the caller to skip NULL check, this function returns "" rather than + * NULL if there is no more words to read. + */ +char *tomoyo_read_token(struct tomoyo_acl_param *param) +{ + char *pos = param->data; + char *del = strchr(pos, ' '); + if (del) + *del++ = '\0'; + else + del = pos + strlen(pos); + param->data = del; + return pos; +} + /** * tomoyo_parse_ulong - Parse an "unsigned long" value. * @@ -81,20 +121,23 @@ void tomoyo_print_ulong(char *buffer, const int buffer_len, /** * tomoyo_parse_name_union - Parse a tomoyo_name_union. * - * @filename: Name or name group. - * @ptr: Pointer to "struct tomoyo_name_union". + * @param: Pointer to "struct tomoyo_acl_param". + * @ptr: Pointer to "struct tomoyo_name_union". * * Returns true on success, false otherwise. */ -bool tomoyo_parse_name_union(const char *filename, +bool tomoyo_parse_name_union(struct tomoyo_acl_param *param, struct tomoyo_name_union *ptr) { - if (!tomoyo_correct_word(filename)) - return false; - if (filename[0] == '@') { - ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP); + char *filename; + if (param->data[0] == '@') { + param->data++; + ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP); return ptr->group != NULL; } + filename = tomoyo_read_token(param); + if (!tomoyo_correct_word(filename)) + return false; ptr->filename = tomoyo_get_name(filename); return ptr->filename != NULL; } @@ -102,39 +145,41 @@ bool tomoyo_parse_name_union(const char *filename, /** * tomoyo_parse_number_union - Parse a tomoyo_number_union. * - * @data: Number or number range or number group. - * @ptr: Pointer to "struct tomoyo_number_union". + * @param: Pointer to "struct tomoyo_acl_param". + * @ptr: Pointer to "struct tomoyo_number_union". * * Returns true on success, false otherwise. */ -bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num) +bool tomoyo_parse_number_union(struct tomoyo_acl_param *param, + struct tomoyo_number_union *ptr) { + char *data; u8 type; unsigned long v; - memset(num, 0, sizeof(*num)); - if (data[0] == '@') { - if (!tomoyo_correct_word(data)) - return false; - num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP); - return num->group != NULL; + memset(ptr, 0, sizeof(*ptr)); + if (param->data[0] == '@') { + param->data++; + ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP); + return ptr->group != NULL; } + data = tomoyo_read_token(param); type = tomoyo_parse_ulong(&v, &data); - if (!type) + if (type == TOMOYO_VALUE_TYPE_INVALID) return false; - num->values[0] = v; - num->value_type[0] = type; + ptr->values[0] = v; + ptr->value_type[0] = type; if (!*data) { - num->values[1] = v; - num->value_type[1] = type; + ptr->values[1] = v; + ptr->value_type[1] = type; return true; } if (*data++ != '-') return false; type = tomoyo_parse_ulong(&v, &data); - if (!type || *data) + if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v) return false; - num->values[1] = v; - num->value_type[1] = type; + ptr->values[1] = v; + ptr->value_type[1] = type; return true; } @@ -258,33 +303,6 @@ void tomoyo_normalize_line(unsigned char *buffer) *dp = '\0'; } -/** - * tomoyo_tokenize - Tokenize string. - * - * @buffer: The line to tokenize. - * @w: Pointer to "char *". - * @size: Sizeof @w . - * - * Returns true on success, false otherwise. - */ -bool tomoyo_tokenize(char *buffer, char *w[], size_t size) -{ - int count = size / sizeof(char *); - int i; - for (i = 0; i < count; i++) - w[i] = ""; - for (i = 0; i < count; i++) { - char *cp = strchr(buffer, ' '); - if (cp) - *cp = '\0'; - w[i] = buffer; - if (!cp) - break; - buffer = cp + 1; - } - return i < count || !*buffer; -} - /** * tomoyo_correct_word2 - Validate a string. * -- 2.34.1