diff options
Diffstat (limited to 'security/tomoyo/gc.c')
| -rw-r--r-- | security/tomoyo/gc.c | 540 | 
1 files changed, 235 insertions, 305 deletions
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index ae135fbbbe9..986a6a75686 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c @@ -8,36 +8,26 @@  #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); -/* Size of an element. */ -static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = { -	[TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group), -	[TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group), -	[TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group), -	[TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator), -	[TOMOYO_ID_TRANSITION_CONTROL] = -	sizeof(struct tomoyo_transition_control), -	[TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager), -	/* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */ -	/* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */ -	/* [TOMOYO_ID_ACL] = -	   tomoyo_acl_size["struct tomoyo_acl_info"->type], */ -	[TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info), -}; - -/* Size of a domain ACL element. */ -static const u8 tomoyo_acl_size[] = { -	[TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl), -	[TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl), -	[TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl), -	[TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl), -	[TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl), -}; -  /**   * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.   * @@ -55,15 +45,11 @@ static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)  	list_for_each_entry(head, &tomoyo_io_buffer_list, list) {  		head->users++;  		spin_unlock(&tomoyo_io_buffer_list_lock); -		if (mutex_lock_interruptible(&head->io_sem)) { -			in_use = true; -			goto out; -		} +		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); -out:  		spin_lock(&tomoyo_io_buffer_list_lock);  		head->users--;  		if (in_use) @@ -77,15 +63,14 @@ out:   * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.   *   * @string: String to check. - * @size:   Memory allocated for @string .   *   * 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, -					  const size_t size) +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); @@ -93,10 +78,7 @@ static bool tomoyo_name_used_by_io_buffer(const char *string,  		int i;  		head->users++;  		spin_unlock(&tomoyo_io_buffer_list_lock); -		if (mutex_lock_interruptible(&head->io_sem)) { -			in_use = true; -			goto out; -		} +		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) @@ -105,7 +87,6 @@ static bool tomoyo_name_used_by_io_buffer(const char *string,  			break;  		}  		mutex_unlock(&head->io_sem); -out:  		spin_lock(&tomoyo_io_buffer_list_lock);  		head->users--;  		if (in_use) @@ -115,84 +96,6 @@ out:  	return in_use;  } -/* Structure for garbage collection. */ -struct tomoyo_gc { -	struct list_head list; -	enum tomoyo_policy_id type; -	size_t size; -	struct list_head *element; -}; -/* List of entries to be deleted. */ -static LIST_HEAD(tomoyo_gc_list); -/* Length of tomoyo_gc_list. */ -static int tomoyo_gc_list_len; - -/** - * tomoyo_add_to_gc - Add an entry to to be deleted list. - * - * @type:    One of values in "enum tomoyo_policy_id". - * @element: Pointer to "struct list_head". - * - * Returns true on success, false otherwise. - * - * Caller holds tomoyo_policy_lock mutex. - * - * Adding an entry needs kmalloc(). Thus, if we try to add thousands of - * entries at once, it will take too long time. Thus, do not add more than 128 - * entries per a scan. But to be able to handle worst case where all entries - * are in-use, we accept one more entry per a scan. - * - * If we use singly linked list using "struct list_head"->prev (which is - * LIST_POISON2), we can avoid kmalloc(). - */ -static bool tomoyo_add_to_gc(const int type, struct list_head *element) -{ -	struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); -	if (!entry) -		return false; -	entry->type = type; -	if (type == TOMOYO_ID_ACL) -		entry->size = tomoyo_acl_size[ -			      container_of(element, -					   typeof(struct tomoyo_acl_info), -					   list)->type]; -	else if (type == TOMOYO_ID_NAME) -		entry->size = strlen(container_of(element, -						  typeof(struct tomoyo_name), -						  head.list)->entry.name) + 1; -	else if (type == TOMOYO_ID_CONDITION) -		entry->size = -			container_of(element, typeof(struct tomoyo_condition), -				     head.list)->size; -	else -		entry->size = tomoyo_element_size[type]; -	entry->element = element; -	list_add(&entry->list, &tomoyo_gc_list); -	list_del_rcu(element); -	return tomoyo_gc_list_len++ < 128; -} - -/** - * tomoyo_element_linked_by_gc - Validate next element of an entry. - * - * @element: Pointer to an element. - * @size:    Size of @element in byte. - * - * Returns true if @element is linked by other elements in the garbage - * collector's queue, false otherwise. - */ -static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size) -{ -	struct tomoyo_gc *p; -	list_for_each_entry(p, &tomoyo_gc_list, list) { -		const u8 *ptr = (const u8 *) p->element->next; -		if (ptr < element || element + size < ptr) -			continue; -		return true; -	} -	return false; -} -  /**   * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".   * @@ -200,7 +103,7 @@ static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size)   *   * Returns nothing.   */ -static void tomoyo_del_transition_control(struct list_head *element) +static inline void tomoyo_del_transition_control(struct list_head *element)  {  	struct tomoyo_transition_control *ptr =  		container_of(element, typeof(*ptr), head.list); @@ -215,7 +118,7 @@ static void tomoyo_del_transition_control(struct list_head *element)   *   * Returns nothing.   */ -static void tomoyo_del_aggregator(struct list_head *element) +static inline void tomoyo_del_aggregator(struct list_head *element)  {  	struct tomoyo_aggregator *ptr =  		container_of(element, typeof(*ptr), head.list); @@ -230,7 +133,7 @@ static void tomoyo_del_aggregator(struct list_head *element)   *   * Returns nothing.   */ -static void tomoyo_del_manager(struct list_head *element) +static inline void tomoyo_del_manager(struct list_head *element)  {  	struct tomoyo_manager *ptr =  		container_of(element, typeof(*ptr), head.list); @@ -293,6 +196,38 @@ static void tomoyo_del_acl(struct list_head *element)  			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;  	}  } @@ -301,44 +236,26 @@ static void tomoyo_del_acl(struct list_head *element)   *   * @element: Pointer to "struct list_head".   * - * Returns true if deleted, false otherwise. + * Returns nothing. + * + * Caller holds tomoyo_policy_lock mutex.   */ -static bool tomoyo_del_domain(struct list_head *element) +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 we don't protect whole execve() operation using SRCU, -	 * we need to recheck domain->users at this point. -	 * -	 * (1) Reader starts SRCU section upon execve(). -	 * (2) Reader traverses tomoyo_domain_list and finds this domain. -	 * (3) Writer marks this domain as deleted. -	 * (4) Garbage collector removes this domain from tomoyo_domain_list -	 *     because this domain is marked as deleted and used by nobody. -	 * (5) Reader saves reference to this domain into -	 *     "struct linux_binprm"->cred->security . -	 * (6) Reader finishes SRCU section, although execve() operation has -	 *     not finished yet. -	 * (7) Garbage collector waits for SRCU synchronization. -	 * (8) Garbage collector kfree() this domain because this domain is -	 *     used by nobody. -	 * (9) Reader finishes execve() operation and restores this domain from -	 *     "struct linux_binprm"->cred->security. -	 * -	 * By updating domain->users at (5), we can solve this race problem -	 * by rechecking domain->users at (8). +	 * 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.  	 */ -	if (atomic_read(&domain->users)) -		return false;  	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); -	return true;  }  /** @@ -387,10 +304,9 @@ void tomoyo_del_condition(struct list_head *element)   *   * Returns nothing.   */ -static void tomoyo_del_name(struct list_head *element) +static inline void tomoyo_del_name(struct list_head *element)  { -	const struct tomoyo_name *ptr = -		container_of(element, typeof(*ptr), head.list); +	/* Nothing to do. */  }  /** @@ -400,7 +316,7 @@ static void tomoyo_del_name(struct list_head *element)   *   * Returns nothing.   */ -static void tomoyo_del_path_group(struct list_head *element) +static inline void tomoyo_del_path_group(struct list_head *element)  {  	struct tomoyo_path_group *member =  		container_of(element, typeof(*member), head.list); @@ -414,7 +330,7 @@ static void tomoyo_del_path_group(struct list_head *element)   *   * Returns nothing.   */ -static void tomoyo_del_group(struct list_head *element) +static inline void tomoyo_del_group(struct list_head *element)  {  	struct tomoyo_group *group =  		container_of(element, typeof(*group), head.list); @@ -422,16 +338,128 @@ static void tomoyo_del_group(struct list_head *element)  }  /** + * 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 void tomoyo_del_number_group(struct list_head *element) +static inline void tomoyo_del_number_group(struct list_head *element)  { -	struct tomoyo_number_group *member = -		container_of(element, typeof(*member), head.list); +	/* 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);  }  /** @@ -440,19 +468,19 @@ static void tomoyo_del_number_group(struct list_head *element)   * @id:          One of values in "enum tomoyo_policy_id".   * @member_list: Pointer to "struct list_head".   * - * Returns true if some elements are deleted, false otherwise. + * Returns nothing.   */ -static bool tomoyo_collect_member(const enum tomoyo_policy_id id, +static void tomoyo_collect_member(const enum tomoyo_policy_id id,  				  struct list_head *member_list)  {  	struct tomoyo_acl_head *member; -	list_for_each_entry(member, member_list, list) { +	struct tomoyo_acl_head *tmp; +	list_for_each_entry_safe(member, tmp, member_list, list) {  		if (!member->is_deleted)  			continue; -		if (!tomoyo_add_to_gc(id, &member->list)) -			return false; +		member->is_deleted = TOMOYO_GC_IN_PROGRESS; +		tomoyo_try_to_gc(id, &member->list);  	} -	return true;  }  /** @@ -460,22 +488,22 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id,   *   * @list: Pointer to "struct list_head".   * - * Returns true if some elements are deleted, false otherwise. + * Returns nothing.   */ -static bool tomoyo_collect_acl(struct list_head *list) +static void tomoyo_collect_acl(struct list_head *list)  {  	struct tomoyo_acl_info *acl; -	list_for_each_entry(acl, list, list) { +	struct tomoyo_acl_info *tmp; +	list_for_each_entry_safe(acl, tmp, list, list) {  		if (!acl->is_deleted)  			continue; -		if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) -			return false; +		acl->is_deleted = TOMOYO_GC_IN_PROGRESS; +		tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);  	} -	return true;  }  /** - * tomoyo_collect_entry - Scan lists for deleted elements. + * tomoyo_collect_entry - Try to kfree() deleted elements.   *   * Returns nothing.   */ @@ -484,174 +512,82 @@ static void tomoyo_collect_entry(void)  	int i;  	enum tomoyo_policy_id id;  	struct tomoyo_policy_namespace *ns; -	int idx; -	if (mutex_lock_interruptible(&tomoyo_policy_lock)) -		return; -	idx = tomoyo_read_lock(); +	mutex_lock(&tomoyo_policy_lock);  	{  		struct tomoyo_domain_info *domain; -		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { -			if (!tomoyo_collect_acl(&domain->acl_info_list)) -				goto unlock; +		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; -			/* -			 * Nobody is referring this domain. But somebody may -			 * refer this domain after successful execve(). -			 * We recheck domain->users after SRCU synchronization. -			 */ -			if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) -				goto unlock; +			tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);  		}  	} -	list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { +	list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {  		for (id = 0; id < TOMOYO_MAX_POLICY; id++) -			if (!tomoyo_collect_member(id, &ns->policy_list[id])) -				goto unlock; +			tomoyo_collect_member(id, &ns->policy_list[id]);  		for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) -			if (!tomoyo_collect_acl(&ns->acl_group[i])) -				goto unlock; +			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; -			default: +			case 1:  				id = TOMOYO_ID_NUMBER_GROUP;  				break; +			default: +				id = TOMOYO_ID_ADDRESS_GROUP; +				break;  			} -			list_for_each_entry(group, list, head.list) { -				if (!tomoyo_collect_member -				    (id, &group->member_list)) -					goto unlock; +			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)) +				    atomic_read(&group->head.users) > 0)  					continue; -				if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, -						      &group->head.list)) -					goto unlock; +				atomic_set(&group->head.users, +					   TOMOYO_GC_IN_PROGRESS); +				tomoyo_try_to_gc(TOMOYO_ID_GROUP, +						 &group->head.list);  			}  		}  	} -	id = TOMOYO_ID_CONDITION; -	for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) { -		struct list_head *list = !i ? -			&tomoyo_condition_list : &tomoyo_name_list[i - 1]; +	for (i = 0; i < TOMOYO_MAX_HASH; i++) { +		struct list_head *list = &tomoyo_name_list[i];  		struct tomoyo_shared_acl_head *ptr; -		list_for_each_entry(ptr, list, list) { -			if (atomic_read(&ptr->users)) +		struct tomoyo_shared_acl_head *tmp; +		list_for_each_entry_safe(ptr, tmp, list, list) { +			if (atomic_read(&ptr->users) > 0)  				continue; -			if (!tomoyo_add_to_gc(id, &ptr->list)) -				goto unlock; +			atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS); +			tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);  		} -		id = TOMOYO_ID_NAME;  	} -unlock: -	tomoyo_read_unlock(idx);  	mutex_unlock(&tomoyo_policy_lock);  }  /** - * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list. - * - * Returns true if some entries were kfree()d, false otherwise. - */ -static bool tomoyo_kfree_entry(void) -{ -	struct tomoyo_gc *p; -	struct tomoyo_gc *tmp; -	bool result = false; - -	list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) { -		struct list_head *element = p->element; - -		/* -		 * list_del_rcu() in tomoyo_add_to_gc() 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() in tomoyo_gc_thread() guarantees -		 * that the list element became no longer referenced by syscall -		 * users. -		 * -		 * However, there are three users which may still be using the -		 * list element. We need to defer until all of these users -		 * forget the list element. -		 * -		 * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain, -		 * group,acl} and "struct tomoyo_io_buffer"->w.domain forget -		 * the list element. -		 */ -		if (tomoyo_struct_used_by_io_buffer(element)) -			continue; -		/* -		 * Secondly, defer until all other elements in the -		 * tomoyo_gc_list list forget the list element. -		 */ -		if (tomoyo_element_linked_by_gc((const u8 *) element, p->size)) -			continue; -		switch (p->type) { -		case TOMOYO_ID_TRANSITION_CONTROL: -			tomoyo_del_transition_control(element); -			break; -		case TOMOYO_ID_AGGREGATOR: -			tomoyo_del_aggregator(element); -			break; -		case TOMOYO_ID_MANAGER: -			tomoyo_del_manager(element); -			break; -		case TOMOYO_ID_CONDITION: -			tomoyo_del_condition(element); -			break; -		case TOMOYO_ID_NAME: -			/* -			 * Thirdly, defer until all "struct tomoyo_io_buffer" -			 * ->r.w[] forget the list element. -			 */ -			if (tomoyo_name_used_by_io_buffer( -			    container_of(element, typeof(struct tomoyo_name), -					 head.list)->entry.name, p->size)) -				continue; -			tomoyo_del_name(element); -			break; -		case TOMOYO_ID_ACL: -			tomoyo_del_acl(element); -			break; -		case TOMOYO_ID_DOMAIN: -			if (!tomoyo_del_domain(element)) -				continue; -			break; -		case TOMOYO_ID_PATH_GROUP: -			tomoyo_del_path_group(element); -			break; -		case TOMOYO_ID_GROUP: -			tomoyo_del_group(element); -			break; -		case TOMOYO_ID_NUMBER_GROUP: -			tomoyo_del_number_group(element); -			break; -		case TOMOYO_MAX_POLICY: -			break; -		} -		tomoyo_memory_free(element); -		list_del(&p->list); -		kfree(p); -		tomoyo_gc_list_len--; -		result = true; -	} -	return result; -} - -/**   * tomoyo_gc_thread - Garbage collector thread function.   *   * @unused: Unused.   * - * In case OOM-killer choose this thread for termination, we create this thread - * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was - * close()d. - *   * Returns 0.   */  static int tomoyo_gc_thread(void *unused) @@ -660,13 +596,7 @@ static int tomoyo_gc_thread(void *unused)  	static DEFINE_MUTEX(tomoyo_gc_mutex);  	if (!mutex_trylock(&tomoyo_gc_mutex))  		goto out; -	daemonize("GC for TOMOYO"); -	do { -		tomoyo_collect_entry(); -		if (list_empty(&tomoyo_gc_list)) -			break; -		synchronize_srcu(&tomoyo_ss); -	} while (tomoyo_kfree_entry()); +	tomoyo_collect_entry();  	{  		struct tomoyo_io_buffer *head;  		struct tomoyo_io_buffer *tmp;  |