gc.c 11.1 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
enum tomoyo_policy_id {
15 16
	TOMOYO_ID_PATH_GROUP,
	TOMOYO_ID_PATH_GROUP_MEMBER,
17 18
	TOMOYO_ID_NUMBER_GROUP,
	TOMOYO_ID_NUMBER_GROUP_MEMBER,
T
Tetsuo Handa 已提交
19 20
	TOMOYO_ID_DOMAIN_INITIALIZER,
	TOMOYO_ID_DOMAIN_KEEPER,
21
	TOMOYO_ID_AGGREGATOR,
T
Tetsuo Handa 已提交
22 23 24 25 26 27 28
	TOMOYO_ID_ALIAS,
	TOMOYO_ID_GLOBALLY_READABLE,
	TOMOYO_ID_PATTERN,
	TOMOYO_ID_NO_REWRITE,
	TOMOYO_ID_MANAGER,
	TOMOYO_ID_NAME,
	TOMOYO_ID_ACL,
29 30
	TOMOYO_ID_DOMAIN,
	TOMOYO_MAX_POLICY
T
Tetsuo Handa 已提交
31 32 33 34 35
};

struct tomoyo_gc_entry {
	struct list_head list;
	int type;
36
	struct list_head *element;
T
Tetsuo Handa 已提交
37 38 39 40 41
};
static LIST_HEAD(tomoyo_gc_queue);
static DEFINE_MUTEX(tomoyo_gc_mutex);

/* Caller holds tomoyo_policy_lock mutex. */
42
static bool tomoyo_add_to_gc(const int type, struct list_head *element)
T
Tetsuo Handa 已提交
43 44 45 46 47 48 49
{
	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);
50
	list_del_rcu(element);
T
Tetsuo Handa 已提交
51 52 53
	return true;
}

54
static void tomoyo_del_allow_read(struct list_head *element)
T
Tetsuo Handa 已提交
55
{
56 57
	struct tomoyo_globally_readable_file_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
58 59 60
	tomoyo_put_name(ptr->filename);
}

61
static void tomoyo_del_file_pattern(struct list_head *element)
T
Tetsuo Handa 已提交
62
{
63 64
	struct tomoyo_pattern_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
65 66 67
	tomoyo_put_name(ptr->pattern);
}

68
static void tomoyo_del_no_rewrite(struct list_head *element)
T
Tetsuo Handa 已提交
69
{
70 71
	struct tomoyo_no_rewrite_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
72 73 74
	tomoyo_put_name(ptr->pattern);
}

75
static void tomoyo_del_domain_initializer(struct list_head *element)
T
Tetsuo Handa 已提交
76
{
77 78
	struct tomoyo_domain_initializer_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
79 80 81 82
	tomoyo_put_name(ptr->domainname);
	tomoyo_put_name(ptr->program);
}

83
static void tomoyo_del_domain_keeper(struct list_head *element)
T
Tetsuo Handa 已提交
84
{
85 86
	struct tomoyo_domain_keeper_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
87 88 89 90
	tomoyo_put_name(ptr->domainname);
	tomoyo_put_name(ptr->program);
}

91
static void tomoyo_del_aggregator(struct list_head *element)
92
{
93 94
	struct tomoyo_aggregator_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
95 96 97 98
	tomoyo_put_name(ptr->original_name);
	tomoyo_put_name(ptr->aggregated_name);
}

99
static void tomoyo_del_alias(struct list_head *element)
T
Tetsuo Handa 已提交
100
{
101 102
	struct tomoyo_alias_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
103 104 105 106
	tomoyo_put_name(ptr->original_name);
	tomoyo_put_name(ptr->aliased_name);
}

107
static void tomoyo_del_manager(struct list_head *element)
T
Tetsuo Handa 已提交
108
{
109 110
	struct tomoyo_policy_manager_entry *ptr =
		container_of(element, typeof(*ptr), head.list);
T
Tetsuo Handa 已提交
111 112 113
	tomoyo_put_name(ptr->manager);
}

114
static void tomoyo_del_acl(struct list_head *element)
T
Tetsuo Handa 已提交
115
{
116 117
	struct tomoyo_acl_info *acl =
		container_of(element, typeof(*acl), list);
T
Tetsuo Handa 已提交
118
	switch (acl->type) {
T
Tetsuo Handa 已提交
119
	case TOMOYO_TYPE_PATH_ACL:
T
Tetsuo Handa 已提交
120
		{
T
Tetsuo Handa 已提交
121
			struct tomoyo_path_acl *entry
T
Tetsuo Handa 已提交
122
				= container_of(acl, typeof(*entry), head);
123
			tomoyo_put_name_union(&entry->name);
T
Tetsuo Handa 已提交
124 125
		}
		break;
T
Tetsuo Handa 已提交
126
	case TOMOYO_TYPE_PATH2_ACL:
T
Tetsuo Handa 已提交
127
		{
T
Tetsuo Handa 已提交
128
			struct tomoyo_path2_acl *entry
T
Tetsuo Handa 已提交
129
				= container_of(acl, typeof(*entry), head);
130 131
			tomoyo_put_name_union(&entry->name1);
			tomoyo_put_name_union(&entry->name2);
T
Tetsuo Handa 已提交
132 133
		}
		break;
134 135 136 137 138 139 140 141
	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 已提交
142
	case TOMOYO_TYPE_MKDEV_ACL:
143
		{
T
Tetsuo Handa 已提交
144
			struct tomoyo_mkdev_acl *entry
145 146 147 148 149 150 151
				= 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 已提交
152 153 154 155 156 157 158 159 160 161
	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 已提交
162 163 164
	}
}

165
static bool tomoyo_del_domain(struct list_head *element)
T
Tetsuo Handa 已提交
166
{
167 168
	struct tomoyo_domain_info *domain =
		container_of(element, typeof(*domain), list);
T
Tetsuo Handa 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	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) {
196
		tomoyo_del_acl(&acl->list);
T
Tetsuo Handa 已提交
197 198 199 200 201 202 203
		tomoyo_memory_free(acl);
	}
	tomoyo_put_name(domain->domainname);
	return true;
}


204
static void tomoyo_del_name(struct list_head *element)
T
Tetsuo Handa 已提交
205
{
206 207
	const struct tomoyo_name_entry *ptr =
		container_of(element, typeof(*ptr), list);
T
Tetsuo Handa 已提交
208 209
}

210
static void tomoyo_del_path_group_member(struct list_head *element)
211
{
212 213
	struct tomoyo_path_group_member *member =
		container_of(element, typeof(*member), head.list);
214 215 216
	tomoyo_put_name(member->member_name);
}

217
static void tomoyo_del_path_group(struct list_head *element)
218
{
219 220
	struct tomoyo_path_group *group =
		container_of(element, typeof(*group), list);
221 222 223
	tomoyo_put_name(group->group_name);
}

224
static void tomoyo_del_number_group_member(struct list_head *element)
225
{
226 227
	struct tomoyo_number_group_member *member =
		container_of(element, typeof(*member), head.list);
228 229
}

230
static void tomoyo_del_number_group(struct list_head *element)
231
{
232 233
	struct tomoyo_number_group *group =
		container_of(element, typeof(*group), list);
234 235 236
	tomoyo_put_name(group->group_name);
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
static struct list_head *tomoyo_policy_list[TOMOYO_MAX_POLICY] = {
	[TOMOYO_ID_GLOBALLY_READABLE] = &tomoyo_globally_readable_list,
	[TOMOYO_ID_PATTERN] = &tomoyo_pattern_list,
	[TOMOYO_ID_NO_REWRITE] = &tomoyo_no_rewrite_list,
	[TOMOYO_ID_DOMAIN_INITIALIZER] = &tomoyo_domain_initializer_list,
	[TOMOYO_ID_DOMAIN_KEEPER] = &tomoyo_domain_keeper_list,
	[TOMOYO_ID_AGGREGATOR] = &tomoyo_aggregator_list,
	[TOMOYO_ID_ALIAS] = &tomoyo_alias_list,
	[TOMOYO_ID_MANAGER] = &tomoyo_policy_manager_list,
};

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 已提交
272 273
static void tomoyo_collect_entry(void)
{
274
	int i;
275 276
	if (mutex_lock_interruptible(&tomoyo_policy_lock))
		return;
277 278 279 280
	for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
		if (tomoyo_policy_list[i])
			if (!tomoyo_collect_member(tomoyo_policy_list[i], i))
				goto unlock;
T
Tetsuo Handa 已提交
281 282 283 284
	}
	{
		struct tomoyo_domain_info *domain;
		list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
285 286
			if (!tomoyo_collect_acl(domain))
				goto unlock;
T
Tetsuo Handa 已提交
287 288 289 290 291 292 293
			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.
			 */
294
			if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
295
				goto unlock;
T
Tetsuo Handa 已提交
296 297
		}
	}
298 299 300 301 302
	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;
303
			if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
304
				goto unlock;
T
Tetsuo Handa 已提交
305 306
		}
	}
307 308 309
	{
		struct tomoyo_path_group *group;
		list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) {
310 311
			tomoyo_collect_member(&group->member_list,
					      TOMOYO_ID_PATH_GROUP_MEMBER);
312 313 314
			if (!list_empty(&group->member_list) ||
			    atomic_read(&group->users))
				continue;
315 316
			if (!tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP,
					      &group->list))
317
				goto unlock;
318 319
		}
	}
320 321
	{
		struct tomoyo_number_group *group;
322 323 324 325
		list_for_each_entry_rcu(group, &tomoyo_number_group_list,
					list) {
			tomoyo_collect_member(&group->member_list,
					      TOMOYO_ID_NUMBER_GROUP_MEMBER);
326 327 328
			if (!list_empty(&group->member_list) ||
			    atomic_read(&group->users))
				continue;
329 330
			if (!tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP,
					      &group->list))
331
				goto unlock;
332 333
		}
	}
334
 unlock:
335
	mutex_unlock(&tomoyo_policy_lock);
T
Tetsuo Handa 已提交
336 337 338 339 340 341 342 343
}

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) {
344
		struct list_head *element = p->element;
T
Tetsuo Handa 已提交
345 346
		switch (p->type) {
		case TOMOYO_ID_DOMAIN_INITIALIZER:
347
			tomoyo_del_domain_initializer(element);
T
Tetsuo Handa 已提交
348 349
			break;
		case TOMOYO_ID_DOMAIN_KEEPER:
350
			tomoyo_del_domain_keeper(element);
T
Tetsuo Handa 已提交
351
			break;
352
		case TOMOYO_ID_AGGREGATOR:
353
			tomoyo_del_aggregator(element);
354
			break;
T
Tetsuo Handa 已提交
355
		case TOMOYO_ID_ALIAS:
356
			tomoyo_del_alias(element);
T
Tetsuo Handa 已提交
357 358
			break;
		case TOMOYO_ID_GLOBALLY_READABLE:
359
			tomoyo_del_allow_read(element);
T
Tetsuo Handa 已提交
360 361
			break;
		case TOMOYO_ID_PATTERN:
362
			tomoyo_del_file_pattern(element);
T
Tetsuo Handa 已提交
363 364
			break;
		case TOMOYO_ID_NO_REWRITE:
365
			tomoyo_del_no_rewrite(element);
T
Tetsuo Handa 已提交
366 367
			break;
		case TOMOYO_ID_MANAGER:
368
			tomoyo_del_manager(element);
T
Tetsuo Handa 已提交
369 370
			break;
		case TOMOYO_ID_NAME:
371
			tomoyo_del_name(element);
T
Tetsuo Handa 已提交
372 373
			break;
		case TOMOYO_ID_ACL:
374
			tomoyo_del_acl(element);
T
Tetsuo Handa 已提交
375 376
			break;
		case TOMOYO_ID_DOMAIN:
377
			if (!tomoyo_del_domain(element))
T
Tetsuo Handa 已提交
378 379
				continue;
			break;
380
		case TOMOYO_ID_PATH_GROUP_MEMBER:
381
			tomoyo_del_path_group_member(element);
382 383
			break;
		case TOMOYO_ID_PATH_GROUP:
384
			tomoyo_del_path_group(element);
385
			break;
386
		case TOMOYO_ID_NUMBER_GROUP_MEMBER:
387
			tomoyo_del_number_group_member(element);
388 389
			break;
		case TOMOYO_ID_NUMBER_GROUP:
390
			tomoyo_del_number_group(element);
T
Tetsuo Handa 已提交
391 392
			break;
		}
393
		tomoyo_memory_free(element);
T
Tetsuo Handa 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
		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);
}