You need to sign in or sign up before continuing.
gc.c 9.4 KB
Newer Older
T
Tetsuo Handa 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * security/tomoyo/gc.c
 *
 * Implementation of the Domain-Based Mandatory Access Control.
 *
 * Copyright (C) 2005-2010  NTT DATA CORPORATION
 *
 */

#include "common.h"
#include <linux/kthread.h>
12
#include <linux/slab.h>
T
Tetsuo Handa 已提交
13 14 15 16

struct tomoyo_gc_entry {
	struct list_head list;
	int type;
17
	struct list_head *element;
T
Tetsuo Handa 已提交
18 19 20 21 22
};
static LIST_HEAD(tomoyo_gc_queue);
static DEFINE_MUTEX(tomoyo_gc_mutex);

/* Caller holds tomoyo_policy_lock mutex. */
23
static bool tomoyo_add_to_gc(const int type, struct list_head *element)
T
Tetsuo Handa 已提交
24 25 26 27 28 29 30
{
	struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
	if (!entry)
		return false;
	entry->type = type;
	entry->element = element;
	list_add(&entry->list, &tomoyo_gc_queue);
31
	list_del_rcu(element);
T
Tetsuo Handa 已提交
32 33 34
	return true;
}

35
static void tomoyo_del_allow_read(struct list_head *element)
T
Tetsuo Handa 已提交
36
{
37 38
	struct tomoyo_globally_readable_file_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
39 40 41
	tomoyo_put_name(ptr->filename);
}

42
static void tomoyo_del_file_pattern(struct list_head *element)
T
Tetsuo Handa 已提交
43
{
44 45
	struct tomoyo_pattern_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
46 47 48
	tomoyo_put_name(ptr->pattern);
}

49
static void tomoyo_del_no_rewrite(struct list_head *element)
T
Tetsuo Handa 已提交
50
{
51 52
	struct tomoyo_no_rewrite_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
53 54 55
	tomoyo_put_name(ptr->pattern);
}

56
static void tomoyo_del_domain_initializer(struct list_head *element)
T
Tetsuo Handa 已提交
57
{
58 59
	struct tomoyo_domain_initializer_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
60 61 62 63
	tomoyo_put_name(ptr->domainname);
	tomoyo_put_name(ptr->program);
}

64
static void tomoyo_del_domain_keeper(struct list_head *element)
T
Tetsuo Handa 已提交
65
{
66 67
	struct tomoyo_domain_keeper_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
68 69 70 71
	tomoyo_put_name(ptr->domainname);
	tomoyo_put_name(ptr->program);
}

72
static void tomoyo_del_aggregator(struct list_head *element)
73
{
74 75
	struct tomoyo_aggregator_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
76 77 78 79
	tomoyo_put_name(ptr->original_name);
	tomoyo_put_name(ptr->aggregated_name);
}

80
static void tomoyo_del_manager(struct list_head *element)
T
Tetsuo Handa 已提交
81
{
82 83
	struct tomoyo_policy_manager_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
84 85 86
	tomoyo_put_name(ptr->manager);
}

87
static void tomoyo_del_acl(struct list_head *element)
T
Tetsuo Handa 已提交
88
{
89 90
	struct tomoyo_acl_info *acl =
		container_of(element, typeof(*acl), list);
T
Tetsuo Handa 已提交
91
	switch (acl->type) {
T
Tetsuo Handa 已提交
92
	case TOMOYO_TYPE_PATH_ACL:
T
Tetsuo Handa 已提交
93
		{
T
Tetsuo Handa 已提交
94
			struct tomoyo_path_acl *entry
T
Tetsuo Handa 已提交
95
				= container_of(acl, typeof(*entry), head);
96
			tomoyo_put_name_union(&entry->name);
T
Tetsuo Handa 已提交
97 98
		}
		break;
T
Tetsuo Handa 已提交
99
	case TOMOYO_TYPE_PATH2_ACL:
T
Tetsuo Handa 已提交
100
		{
T
Tetsuo Handa 已提交
101
			struct tomoyo_path2_acl *entry
T
Tetsuo Handa 已提交
102
				= container_of(acl, typeof(*entry), head);
103 104
			tomoyo_put_name_union(&entry->name1);
			tomoyo_put_name_union(&entry->name2);
T
Tetsuo Handa 已提交
105 106
		}
		break;
107 108 109 110 111 112 113 114
	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;
T
Tetsuo Handa 已提交
115
	case TOMOYO_TYPE_MKDEV_ACL:
116
		{
T
Tetsuo Handa 已提交
117
			struct tomoyo_mkdev_acl *entry
118 119 120 121 122 123 124
				= 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;
T
Tetsuo Handa 已提交
125 126 127 128 129 130 131 132 133 134
	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;
T
Tetsuo Handa 已提交
135 136 137
	}
}

138
static bool tomoyo_del_domain(struct list_head *element)
T
Tetsuo Handa 已提交
139
{
140 141
	struct tomoyo_domain_info *domain =
		container_of(element, typeof(*domain), list);
T
Tetsuo Handa 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	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).
	 */
	if (atomic_read(&domain->users))
		return false;
	list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
169
		tomoyo_del_acl(&acl->list);
T
Tetsuo Handa 已提交
170 171 172 173 174 175 176
		tomoyo_memory_free(acl);
	}
	tomoyo_put_name(domain->domainname);
	return true;
}


177
static void tomoyo_del_name(struct list_head *element)
T
Tetsuo Handa 已提交
178
{
179 180
	const struct tomoyo_name_entry *ptr =
		container_of(element, typeof(*ptr), list);
T
Tetsuo Handa 已提交
181 182
}

183
static void tomoyo_del_path_group(struct list_head *element)
184
{
185
	struct tomoyo_path_group *member =
186
		container_of(element, typeof(*member), head.list);
187 188 189
	tomoyo_put_name(member->member_name);
}

190
static void tomoyo_del_group(struct list_head *element)
191
{
192
	struct tomoyo_group *group =
193
		container_of(element, typeof(*group), list);
194 195 196
	tomoyo_put_name(group->group_name);
}

197
static void tomoyo_del_number_group(struct list_head *element)
198
{
199 200
	struct tomoyo_number_group *member =
		container_of(element, typeof(*member), head.list);
201 202
}

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
static bool tomoyo_collect_member(struct list_head *member_list, int id)
{
	struct tomoyo_acl_head *member;
	list_for_each_entry(member, member_list, list) {
		if (!member->is_deleted)
			continue;
		if (!tomoyo_add_to_gc(id, &member->list))
			return false;
	}
        return true;
}

static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
{
	struct tomoyo_acl_info *acl;
	list_for_each_entry(acl, &domain->acl_info_list, list) {
		if (!acl->is_deleted)
			continue;
		if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
			return false;
	}
	return true;
}

T
Tetsuo Handa 已提交
227 228
static void tomoyo_collect_entry(void)
{
229
	int i;
230 231
	if (mutex_lock_interruptible(&tomoyo_policy_lock))
		return;
232
	for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
233 234
		if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
			goto unlock;
T
Tetsuo Handa 已提交
235 236 237 238
	}
	{
		struct tomoyo_domain_info *domain;
		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
239 240
			if (!tomoyo_collect_acl(domain))
				goto unlock;
T
Tetsuo Handa 已提交
241 242 243 244 245 246 247
			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.
			 */
248
			if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
249
				goto unlock;
T
Tetsuo Handa 已提交
250 251
		}
	}
252 253 254 255 256
	for (i = 0; i < TOMOYO_MAX_HASH; i++) {
		struct tomoyo_name_entry *ptr;
		list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
			if (atomic_read(&ptr->users))
				continue;
257
			if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
258
				goto unlock;
T
Tetsuo Handa 已提交
259 260
		}
	}
261 262 263
	for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
		struct list_head *list = &tomoyo_group_list[i];
		int id;
264
		struct tomoyo_group *group;
265 266 267 268 269 270 271
		switch (i) {
		case 0:
			id = TOMOYO_ID_PATH_GROUP;
			break;
		default:
			id = TOMOYO_ID_NUMBER_GROUP;
			break;
272
		}
273 274 275
		list_for_each_entry(group, list, list) {
			if (!tomoyo_collect_member(&group->member_list, id))
				goto unlock;
276 277 278
			if (!list_empty(&group->member_list) ||
			    atomic_read(&group->users))
				continue;
279
			if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
280
				goto unlock;
281 282
		}
	}
283
 unlock:
284
	mutex_unlock(&tomoyo_policy_lock);
T
Tetsuo Handa 已提交
285 286 287 288 289 290 291 292
}

static void tomoyo_kfree_entry(void)
{
	struct tomoyo_gc_entry *p;
	struct tomoyo_gc_entry *tmp;

	list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
293
		struct list_head *element = p->element;
T
Tetsuo Handa 已提交
294 295
		switch (p->type) {
		case TOMOYO_ID_DOMAIN_INITIALIZER:
296
			tomoyo_del_domain_initializer(element);
T
Tetsuo Handa 已提交
297 298
			break;
		case TOMOYO_ID_DOMAIN_KEEPER:
299
			tomoyo_del_domain_keeper(element);
T
Tetsuo Handa 已提交
300
			break;
301
		case TOMOYO_ID_AGGREGATOR:
302
			tomoyo_del_aggregator(element);
303
			break;
T
Tetsuo Handa 已提交
304
		case TOMOYO_ID_GLOBALLY_READABLE:
305
			tomoyo_del_allow_read(element);
T
Tetsuo Handa 已提交
306 307
			break;
		case TOMOYO_ID_PATTERN:
308
			tomoyo_del_file_pattern(element);
T
Tetsuo Handa 已提交
309 310
			break;
		case TOMOYO_ID_NO_REWRITE:
311
			tomoyo_del_no_rewrite(element);
T
Tetsuo Handa 已提交
312 313
			break;
		case TOMOYO_ID_MANAGER:
314
			tomoyo_del_manager(element);
T
Tetsuo Handa 已提交
315 316
			break;
		case TOMOYO_ID_NAME:
317
			tomoyo_del_name(element);
T
Tetsuo Handa 已提交
318 319
			break;
		case TOMOYO_ID_ACL:
320
			tomoyo_del_acl(element);
T
Tetsuo Handa 已提交
321 322
			break;
		case TOMOYO_ID_DOMAIN:
323
			if (!tomoyo_del_domain(element))
T
Tetsuo Handa 已提交
324 325
				continue;
			break;
326
		case TOMOYO_ID_PATH_GROUP:
327
			tomoyo_del_path_group(element);
328
			break;
329 330
		case TOMOYO_ID_GROUP:
			tomoyo_del_group(element);
331 332
			break;
		case TOMOYO_ID_NUMBER_GROUP:
333
			tomoyo_del_number_group(element);
T
Tetsuo Handa 已提交
334 335
			break;
		}
336
		tomoyo_memory_free(element);
T
Tetsuo Handa 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
		list_del(&p->list);
		kfree(p);
	}
}

static int tomoyo_gc_thread(void *unused)
{
	daemonize("GC for TOMOYO");
	if (mutex_trylock(&tomoyo_gc_mutex)) {
		int i;
		for (i = 0; i < 10; i++) {
			tomoyo_collect_entry();
			if (list_empty(&tomoyo_gc_queue))
				break;
			synchronize_srcu(&tomoyo_ss);
			tomoyo_kfree_entry();
		}
		mutex_unlock(&tomoyo_gc_mutex);
	}
	do_exit(0);
}

void tomoyo_run_gc(void)
{
	struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
						  "GC for TOMOYO");
	if (!IS_ERR(task))
		wake_up_process(task);
}