From 32997144fd9925fc4d506a16990a0c405f766526 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 26 Jun 2011 23:19:28 +0900 Subject: TOMOYO: Add ACL group support. ACL group allows administrator to globally grant not only "file read" permission but also other permissions. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 51 +++++++++++++++++++++++++++++++++++++++++------- security/tomoyo/common.h | 7 +++++++ security/tomoyo/domain.c | 23 +++++++++++++++++++++- security/tomoyo/gc.c | 16 ++++++++++++--- security/tomoyo/memory.c | 2 ++ 5 files changed, 88 insertions(+), 11 deletions(-) (limited to 'security') diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 6580ef35074b..507ebf01e43b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -896,6 +896,12 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) domain->profile = (u8) profile; return 0; } + if (sscanf(data, "use_group %u\n", &profile) == 1 + && profile < TOMOYO_MAX_ACL_GROUPS) { + if (!is_delete) + domain->group = (u8) profile; + return 0; + } if (!strcmp(data, "quota_exceeded")) { domain->quota_warned = !is_delete; return 0; @@ -908,7 +914,7 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) } /** - * tomoyo_set_group - Print category name. + * tomoyo_set_group - Print "acl_group " header keyword and category name. * * @head: Pointer to "struct tomoyo_io_buffer". * @category: Category name. @@ -918,6 +924,9 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) static void tomoyo_set_group(struct tomoyo_io_buffer *head, const char *category) { + if (head->type == TOMOYO_EXCEPTIONPOLICY) + tomoyo_io_printf(head, "acl_group %u ", + head->r.acl_group_index); tomoyo_set_string(head, category); } @@ -1041,17 +1050,17 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, /** * tomoyo_read_domain2 - Read domain policy. * - * @head: Pointer to "struct tomoyo_io_buffer". - * @domain: Pointer to "struct tomoyo_domain_info". + * @head: Pointer to "struct tomoyo_io_buffer". + * @list: Pointer to "struct list_head". * * Caller holds tomoyo_read_lock(). * * Returns true on success, false otherwise. */ static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, - struct tomoyo_domain_info *domain) + struct list_head *list) { - list_for_each_cookie(head->r.acl, &domain->acl_info_list) { + list_for_each_cookie(head->r.acl, list) { struct tomoyo_acl_info *ptr = list_entry(head->r.acl, typeof(*ptr), list); if (!tomoyo_print_entry(head, ptr)) @@ -1085,6 +1094,8 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) tomoyo_set_lf(head); tomoyo_io_printf(head, "use_profile %u\n", domain->profile); + tomoyo_io_printf(head, "use_group %u\n", + domain->group); if (domain->quota_warned) tomoyo_set_string(head, "quota_exceeded\n"); if (domain->transition_failed) @@ -1093,7 +1104,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) tomoyo_set_lf(head); /* fall through */ case 1: - if (!tomoyo_read_domain2(head, domain)) + if (!tomoyo_read_domain2(head, &domain->acl_info_list)) return; head->r.step++; if (!tomoyo_set_lf(head)) @@ -1262,6 +1273,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) }; u8 i; param.is_delete = tomoyo_str_starts(¶m.data, "delete "); + if (!param.is_delete && tomoyo_str_starts(¶m.data, "select ") && + !strcmp(param.data, "execute_only")) { + head->r.print_execute_only = true; + return 0; + } + /* Don't allow updating policies by non manager programs. */ + if (!tomoyo_manager()) + return -EPERM; if (tomoyo_str_starts(¶m.data, "aggregator ")) return tomoyo_write_aggregator(¶m); for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) @@ -1270,6 +1289,14 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) for (i = 0; i < TOMOYO_MAX_GROUP; i++) if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) return tomoyo_write_group(¶m, i); + if (tomoyo_str_starts(¶m.data, "acl_group ")) { + unsigned int group; + char *data; + group = simple_strtoul(param.data, &data, 10); + if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') + return tomoyo_write_domain2(&tomoyo_acl_group[group], + data, param.is_delete); + } return -EINVAL; } @@ -1392,6 +1419,15 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) head->r.step++; if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) return; + while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP + + TOMOYO_MAX_ACL_GROUPS) { + head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY + - TOMOYO_MAX_GROUP; + if (!tomoyo_read_domain2(head, &tomoyo_acl_group + [head->r.acl_group_index])) + return; + head->r.step++; + } head->r.eof = true; } @@ -1914,7 +1950,8 @@ int tomoyo_write_control(struct tomoyo_io_buffer *head, return -EFAULT; /* Don't allow updating policies by non manager programs. */ if (head->write != tomoyo_write_pid && - head->write != tomoyo_write_domain && !tomoyo_manager()) + head->write != tomoyo_write_domain && + head->write != tomoyo_write_exception && !tomoyo_manager()) return -EPERM; if (mutex_lock_interruptible(&head->io_sem)) return -EINTR; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index f40ec1fcbc5d..4bc3975516cb 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -38,6 +38,9 @@ struct linux_binprm; /* Profile number is an integer between 0 and 255. */ #define TOMOYO_MAX_PROFILES 256 +/* Group number is an integer between 0 and 255. */ +#define TOMOYO_MAX_ACL_GROUPS 256 + /* Index numbers for operation mode. */ enum tomoyo_mode_index { TOMOYO_CONFIG_DISABLED, @@ -357,6 +360,7 @@ struct tomoyo_domain_info { /* Name of this domain. Never NULL. */ const struct tomoyo_path_info *domainname; u8 profile; /* Profile number to use. */ + u8 group; /* Group number to use. */ bool is_deleted; /* Delete flag. */ bool quota_warned; /* Quota warnning flag. */ bool transition_failed; /* Domain transition failed flag. */ @@ -446,6 +450,7 @@ struct tomoyo_io_buffer { int step; int query_index; u16 index; + u8 acl_group_index; u8 bit; u8 w_pos; bool eof; @@ -666,6 +671,8 @@ extern struct mutex tomoyo_policy_lock; /* Has /sbin/init started? */ extern bool tomoyo_policy_loaded; +extern struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS]; + /* The kernel's domain. */ extern struct tomoyo_domain_info tomoyo_kernel_domain; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index cb5d2b05c244..af5f325e2f33 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -12,6 +12,9 @@ /* Variables definitions.*/ +/* The global ACL referred by "use_group" keyword. */ +struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS]; + /* The initial domain. */ struct tomoyo_domain_info tomoyo_kernel_domain; @@ -125,14 +128,27 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, return error; } +/** + * tomoyo_check_acl - Do permission check. + * + * @r: Pointer to "struct tomoyo_request_info". + * @check_entry: Callback function to check type specific parameters. + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ void tomoyo_check_acl(struct tomoyo_request_info *r, bool (*check_entry) (struct tomoyo_request_info *, const struct tomoyo_acl_info *)) { const struct tomoyo_domain_info *domain = r->domain; struct tomoyo_acl_info *ptr; + bool retried = false; + const struct list_head *list = &domain->acl_info_list; - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { +retry: + list_for_each_entry_rcu(ptr, list, list) { if (ptr->is_deleted || ptr->type != r->param_type) continue; if (check_entry(r, ptr)) { @@ -140,6 +156,11 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, return; } } + if (!retried) { + retried = true; + list = &tomoyo_acl_group[domain->group]; + goto retry; + } r->granted = false; } diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index de14030823cd..412ee8309c23 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c @@ -265,10 +265,17 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id, return true; } -static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain) +/** + * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info". + * + * @list: Pointer to "struct list_head". + * + * Returns true if some elements are deleted, false otherwise. + */ +static bool tomoyo_collect_acl(struct list_head *list) { struct tomoyo_acl_info *acl; - list_for_each_entry(acl, &domain->acl_info_list, list) { + list_for_each_entry(acl, list, list) { if (!acl->is_deleted) continue; if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) @@ -291,10 +298,13 @@ static void tomoyo_collect_entry(void) if (!tomoyo_collect_member(i, &tomoyo_policy_list[i])) goto unlock; } + for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) + if (!tomoyo_collect_acl(&tomoyo_acl_group[i])) + goto unlock; { struct tomoyo_domain_info *domain; list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { - if (!tomoyo_collect_acl(domain)) + if (!tomoyo_collect_acl(&domain->acl_info_list)) goto unlock; if (!domain->is_deleted || atomic_read(&domain->users)) continue; diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 598282cd0bdd..7a0493943d6d 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c @@ -213,6 +213,8 @@ void __init tomoyo_mm_init(void) for (idx = 0; idx < TOMOYO_MAX_HASH; idx++) INIT_LIST_HEAD(&tomoyo_name_list[idx]); INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); + for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) + INIT_LIST_HEAD(&tomoyo_acl_group[idx]); tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); idx = tomoyo_read_lock(); -- cgit v1.2.3