diff options
Diffstat (limited to 'ANDROID_3.4.5/security/tomoyo/gc.c')
-rw-r--r-- | ANDROID_3.4.5/security/tomoyo/gc.c | 655 |
1 files changed, 0 insertions, 655 deletions
diff --git a/ANDROID_3.4.5/security/tomoyo/gc.c b/ANDROID_3.4.5/security/tomoyo/gc.c deleted file mode 100644 index 986a6a75..00000000 --- a/ANDROID_3.4.5/security/tomoyo/gc.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * security/tomoyo/gc.c - * - * Copyright (C) 2005-2011 NTT DATA CORPORATION - */ - -#include "common.h" -#include <linux/kthread.h> -#include <linux/slab.h> - -/** - * tomoyo_memory_free - Free memory for elements. - * - * @ptr: Pointer to allocated memory. - * - * Returns nothing. - * - * Caller holds tomoyo_policy_lock mutex. - */ -static inline void tomoyo_memory_free(void *ptr) -{ - tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr); - kfree(ptr); -} - -/* The list for "struct tomoyo_io_buffer". */ -static LIST_HEAD(tomoyo_io_buffer_list); -/* Lock for protecting tomoyo_io_buffer_list. */ -static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); - -/** - * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not. - * - * @element: Pointer to "struct list_head". - * - * Returns true if @element is used by /sys/kernel/security/tomoyo/ users, - * false otherwise. - */ -static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element) -{ - struct tomoyo_io_buffer *head; - bool in_use = false; - - spin_lock(&tomoyo_io_buffer_list_lock); - list_for_each_entry(head, &tomoyo_io_buffer_list, list) { - head->users++; - spin_unlock(&tomoyo_io_buffer_list_lock); - mutex_lock(&head->io_sem); - if (head->r.domain == element || head->r.group == element || - head->r.acl == element || &head->w.domain->list == element) - in_use = true; - mutex_unlock(&head->io_sem); - spin_lock(&tomoyo_io_buffer_list_lock); - head->users--; - if (in_use) - break; - } - spin_unlock(&tomoyo_io_buffer_list_lock); - return in_use; -} - -/** - * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not. - * - * @string: String to check. - * - * Returns true if @string is used by /sys/kernel/security/tomoyo/ users, - * false otherwise. - */ -static bool tomoyo_name_used_by_io_buffer(const char *string) -{ - struct tomoyo_io_buffer *head; - const size_t size = strlen(string) + 1; - bool in_use = false; - - spin_lock(&tomoyo_io_buffer_list_lock); - list_for_each_entry(head, &tomoyo_io_buffer_list, list) { - int i; - head->users++; - spin_unlock(&tomoyo_io_buffer_list_lock); - mutex_lock(&head->io_sem); - for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) { - const char *w = head->r.w[i]; - if (w < string || w > string + size) - continue; - in_use = true; - break; - } - mutex_unlock(&head->io_sem); - spin_lock(&tomoyo_io_buffer_list_lock); - head->users--; - if (in_use) - break; - } - spin_unlock(&tomoyo_io_buffer_list_lock); - return in_use; -} - -/** - * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_transition_control(struct list_head *element) -{ - struct tomoyo_transition_control *ptr = - container_of(element, typeof(*ptr), head.list); - tomoyo_put_name(ptr->domainname); - tomoyo_put_name(ptr->program); -} - -/** - * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_aggregator(struct list_head *element) -{ - struct tomoyo_aggregator *ptr = - container_of(element, typeof(*ptr), head.list); - tomoyo_put_name(ptr->original_name); - tomoyo_put_name(ptr->aggregated_name); -} - -/** - * tomoyo_del_manager - Delete members in "struct tomoyo_manager". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_manager(struct list_head *element) -{ - struct tomoyo_manager *ptr = - container_of(element, typeof(*ptr), head.list); - tomoyo_put_name(ptr->manager); -} - -/** - * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static void tomoyo_del_acl(struct list_head *element) -{ - struct tomoyo_acl_info *acl = - container_of(element, typeof(*acl), list); - tomoyo_put_condition(acl->cond); - switch (acl->type) { - case TOMOYO_TYPE_PATH_ACL: - { - struct tomoyo_path_acl *entry - = container_of(acl, typeof(*entry), head); - tomoyo_put_name_union(&entry->name); - } - break; - case TOMOYO_TYPE_PATH2_ACL: - { - struct tomoyo_path2_acl *entry - = container_of(acl, typeof(*entry), head); - tomoyo_put_name_union(&entry->name1); - tomoyo_put_name_union(&entry->name2); - } - break; - case TOMOYO_TYPE_PATH_NUMBER_ACL: - { - struct tomoyo_path_number_acl *entry - = container_of(acl, typeof(*entry), head); - tomoyo_put_name_union(&entry->name); - tomoyo_put_number_union(&entry->number); - } - break; - case TOMOYO_TYPE_MKDEV_ACL: - { - struct tomoyo_mkdev_acl *entry - = container_of(acl, typeof(*entry), head); - tomoyo_put_name_union(&entry->name); - tomoyo_put_number_union(&entry->mode); - tomoyo_put_number_union(&entry->major); - tomoyo_put_number_union(&entry->minor); - } - break; - case TOMOYO_TYPE_MOUNT_ACL: - { - struct tomoyo_mount_acl *entry - = container_of(acl, typeof(*entry), head); - tomoyo_put_name_union(&entry->dev_name); - tomoyo_put_name_union(&entry->dir_name); - tomoyo_put_name_union(&entry->fs_type); - tomoyo_put_number_union(&entry->flags); - } - break; - case TOMOYO_TYPE_ENV_ACL: - { - struct tomoyo_env_acl *entry = - container_of(acl, typeof(*entry), head); - - tomoyo_put_name(entry->env); - } - break; - case TOMOYO_TYPE_INET_ACL: - { - struct tomoyo_inet_acl *entry = - container_of(acl, typeof(*entry), head); - - tomoyo_put_group(entry->address.group); - tomoyo_put_number_union(&entry->port); - } - break; - case TOMOYO_TYPE_UNIX_ACL: - { - struct tomoyo_unix_acl *entry = - container_of(acl, typeof(*entry), head); - - tomoyo_put_name_union(&entry->name); - } - break; - case TOMOYO_TYPE_MANUAL_TASK_ACL: - { - struct tomoyo_task_acl *entry = - container_of(acl, typeof(*entry), head); - tomoyo_put_name(entry->domainname); - } - break; - } -} - -/** - * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - * - * Caller holds tomoyo_policy_lock mutex. - */ -static inline void tomoyo_del_domain(struct list_head *element) -{ - struct tomoyo_domain_info *domain = - container_of(element, typeof(*domain), list); - struct tomoyo_acl_info *acl; - struct tomoyo_acl_info *tmp; - /* - * Since this domain is referenced from neither - * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete - * elements without checking for is_deleted flag. - */ - list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { - tomoyo_del_acl(&acl->list); - tomoyo_memory_free(acl); - } - tomoyo_put_name(domain->domainname); -} - -/** - * tomoyo_del_condition - Delete members in "struct tomoyo_condition". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -void tomoyo_del_condition(struct list_head *element) -{ - struct tomoyo_condition *cond = container_of(element, typeof(*cond), - head.list); - const u16 condc = cond->condc; - const u16 numbers_count = cond->numbers_count; - const u16 names_count = cond->names_count; - const u16 argc = cond->argc; - const u16 envc = cond->envc; - unsigned int i; - const struct tomoyo_condition_element *condp - = (const struct tomoyo_condition_element *) (cond + 1); - struct tomoyo_number_union *numbers_p - = (struct tomoyo_number_union *) (condp + condc); - struct tomoyo_name_union *names_p - = (struct tomoyo_name_union *) (numbers_p + numbers_count); - const struct tomoyo_argv *argv - = (const struct tomoyo_argv *) (names_p + names_count); - const struct tomoyo_envp *envp - = (const struct tomoyo_envp *) (argv + argc); - for (i = 0; i < numbers_count; i++) - tomoyo_put_number_union(numbers_p++); - for (i = 0; i < names_count; i++) - tomoyo_put_name_union(names_p++); - for (i = 0; i < argc; argv++, i++) - tomoyo_put_name(argv->value); - for (i = 0; i < envc; envp++, i++) { - tomoyo_put_name(envp->name); - tomoyo_put_name(envp->value); - } -} - -/** - * tomoyo_del_name - Delete members in "struct tomoyo_name". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_name(struct list_head *element) -{ - /* Nothing to do. */ -} - -/** - * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_path_group(struct list_head *element) -{ - struct tomoyo_path_group *member = - container_of(element, typeof(*member), head.list); - tomoyo_put_name(member->member_name); -} - -/** - * tomoyo_del_group - Delete "struct tomoyo_group". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_group(struct list_head *element) -{ - struct tomoyo_group *group = - container_of(element, typeof(*group), head.list); - tomoyo_put_name(group->group_name); -} - -/** - * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_address_group(struct list_head *element) -{ - /* Nothing to do. */ -} - -/** - * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". - * - * @element: Pointer to "struct list_head". - * - * Returns nothing. - */ -static inline void tomoyo_del_number_group(struct list_head *element) -{ - /* Nothing to do. */ -} - -/** - * tomoyo_try_to_gc - Try to kfree() an entry. - * - * @type: One of values in "enum tomoyo_policy_id". - * @element: Pointer to "struct list_head". - * - * Returns nothing. - * - * Caller holds tomoyo_policy_lock mutex. - */ -static void tomoyo_try_to_gc(const enum tomoyo_policy_id type, - struct list_head *element) -{ - /* - * __list_del_entry() guarantees that the list element became no longer - * reachable from the list which the element was originally on (e.g. - * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the - * list element became no longer referenced by syscall users. - */ - __list_del_entry(element); - mutex_unlock(&tomoyo_policy_lock); - synchronize_srcu(&tomoyo_ss); - /* - * However, there are two users which may still be using the list - * element. We need to defer until both users forget this element. - * - * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl} - * and "struct tomoyo_io_buffer"->w.domain forget this element. - */ - if (tomoyo_struct_used_by_io_buffer(element)) - goto reinject; - switch (type) { - case TOMOYO_ID_TRANSITION_CONTROL: - tomoyo_del_transition_control(element); - break; - case TOMOYO_ID_MANAGER: - tomoyo_del_manager(element); - break; - case TOMOYO_ID_AGGREGATOR: - tomoyo_del_aggregator(element); - break; - case TOMOYO_ID_GROUP: - tomoyo_del_group(element); - break; - case TOMOYO_ID_PATH_GROUP: - tomoyo_del_path_group(element); - break; - case TOMOYO_ID_ADDRESS_GROUP: - tomoyo_del_address_group(element); - break; - case TOMOYO_ID_NUMBER_GROUP: - tomoyo_del_number_group(element); - break; - case TOMOYO_ID_CONDITION: - tomoyo_del_condition(element); - break; - case TOMOYO_ID_NAME: - /* - * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[] - * forget this element. - */ - if (tomoyo_name_used_by_io_buffer - (container_of(element, typeof(struct tomoyo_name), - head.list)->entry.name)) - goto reinject; - tomoyo_del_name(element); - break; - case TOMOYO_ID_ACL: - tomoyo_del_acl(element); - break; - case TOMOYO_ID_DOMAIN: - /* - * Don't kfree() until all "struct cred"->security forget this - * element. - */ - if (atomic_read(&container_of - (element, typeof(struct tomoyo_domain_info), - list)->users)) - goto reinject; - break; - case TOMOYO_MAX_POLICY: - break; - } - mutex_lock(&tomoyo_policy_lock); - if (type == TOMOYO_ID_DOMAIN) - tomoyo_del_domain(element); - tomoyo_memory_free(element); - return; -reinject: - /* - * We can safely reinject this element here bacause - * (1) Appending list elements and removing list elements are protected - * by tomoyo_policy_lock mutex. - * (2) Only this function removes list elements and this function is - * exclusively executed by tomoyo_gc_mutex mutex. - * are true. - */ - mutex_lock(&tomoyo_policy_lock); - list_add_rcu(element, element->prev); -} - -/** - * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head". - * - * @id: One of values in "enum tomoyo_policy_id". - * @member_list: Pointer to "struct list_head". - * - * Returns nothing. - */ -static void tomoyo_collect_member(const enum tomoyo_policy_id id, - struct list_head *member_list) -{ - struct tomoyo_acl_head *member; - struct tomoyo_acl_head *tmp; - list_for_each_entry_safe(member, tmp, member_list, list) { - if (!member->is_deleted) - continue; - member->is_deleted = TOMOYO_GC_IN_PROGRESS; - tomoyo_try_to_gc(id, &member->list); - } -} - -/** - * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info". - * - * @list: Pointer to "struct list_head". - * - * Returns nothing. - */ -static void tomoyo_collect_acl(struct list_head *list) -{ - struct tomoyo_acl_info *acl; - struct tomoyo_acl_info *tmp; - list_for_each_entry_safe(acl, tmp, list, list) { - if (!acl->is_deleted) - continue; - acl->is_deleted = TOMOYO_GC_IN_PROGRESS; - tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list); - } -} - -/** - * tomoyo_collect_entry - Try to kfree() deleted elements. - * - * Returns nothing. - */ -static void tomoyo_collect_entry(void) -{ - int i; - enum tomoyo_policy_id id; - struct tomoyo_policy_namespace *ns; - mutex_lock(&tomoyo_policy_lock); - { - struct tomoyo_domain_info *domain; - struct tomoyo_domain_info *tmp; - list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list, - list) { - tomoyo_collect_acl(&domain->acl_info_list); - if (!domain->is_deleted || atomic_read(&domain->users)) - continue; - tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list); - } - } - list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { - for (id = 0; id < TOMOYO_MAX_POLICY; id++) - tomoyo_collect_member(id, &ns->policy_list[id]); - for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) - tomoyo_collect_acl(&ns->acl_group[i]); - } - { - struct tomoyo_shared_acl_head *ptr; - struct tomoyo_shared_acl_head *tmp; - list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list, - list) { - if (atomic_read(&ptr->users) > 0) - continue; - atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); - tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list); - } - } - list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) { - for (i = 0; i < TOMOYO_MAX_GROUP; i++) { - struct list_head *list = &ns->group_list[i]; - struct tomoyo_group *group; - struct tomoyo_group *tmp; - switch (i) { - case 0: - id = TOMOYO_ID_PATH_GROUP; - break; - case 1: - id = TOMOYO_ID_NUMBER_GROUP; - break; - default: - id = TOMOYO_ID_ADDRESS_GROUP; - break; - } - list_for_each_entry_safe(group, tmp, list, head.list) { - tomoyo_collect_member(id, &group->member_list); - if (!list_empty(&group->member_list) || - atomic_read(&group->head.users) > 0) - continue; - atomic_set(&group->head.users, - TOMOYO_GC_IN_PROGRESS); - tomoyo_try_to_gc(TOMOYO_ID_GROUP, - &group->head.list); - } - } - } - for (i = 0; i < TOMOYO_MAX_HASH; i++) { - struct list_head *list = &tomoyo_name_list[i]; - struct tomoyo_shared_acl_head *ptr; - struct tomoyo_shared_acl_head *tmp; - list_for_each_entry_safe(ptr, tmp, list, list) { - if (atomic_read(&ptr->users) > 0) - continue; - atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); - tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list); - } - } - mutex_unlock(&tomoyo_policy_lock); -} - -/** - * tomoyo_gc_thread - Garbage collector thread function. - * - * @unused: Unused. - * - * Returns 0. - */ -static int tomoyo_gc_thread(void *unused) -{ - /* Garbage collector thread is exclusive. */ - static DEFINE_MUTEX(tomoyo_gc_mutex); - if (!mutex_trylock(&tomoyo_gc_mutex)) - goto out; - tomoyo_collect_entry(); - { - struct tomoyo_io_buffer *head; - struct tomoyo_io_buffer *tmp; - - spin_lock(&tomoyo_io_buffer_list_lock); - list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list, - list) { - if (head->users) - continue; - list_del(&head->list); - kfree(head->read_buf); - kfree(head->write_buf); - kfree(head); - } - spin_unlock(&tomoyo_io_buffer_list_lock); - } - mutex_unlock(&tomoyo_gc_mutex); -out: - /* This acts as do_exit(0). */ - return 0; -} - -/** - * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users. - * - * @head: Pointer to "struct tomoyo_io_buffer". - * @is_register: True if register, false if unregister. - * - * Returns nothing. - */ -void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register) -{ - bool is_write = false; - - spin_lock(&tomoyo_io_buffer_list_lock); - if (is_register) { - head->users = 1; - list_add(&head->list, &tomoyo_io_buffer_list); - } else { - is_write = head->write_buf != NULL; - if (!--head->users) { - list_del(&head->list); - kfree(head->read_buf); - kfree(head->write_buf); - kfree(head); - } - } - spin_unlock(&tomoyo_io_buffer_list_lock); - if (is_write) { - struct task_struct *task = kthread_create(tomoyo_gc_thread, - NULL, - "GC for TOMOYO"); - if (!IS_ERR(task)) - wake_up_process(task); - } -} |