common.c 63.2 KB
Newer Older
1 2 3 4 5
/*
 * security/tomoyo/common.c
 *
 * Common functions for TOMOYO.
 *
6
 * Copyright (C) 2005-2010  NTT DATA CORPORATION
7 8 9
 */

#include <linux/uaccess.h>
10
#include <linux/slab.h>
11 12 13
#include <linux/security.h>
#include "common.h"

T
Tetsuo Handa 已提交
14 15 16 17 18 19
/* String table for operation mode. */
const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
	[TOMOYO_CONFIG_DISABLED]   = "disabled",
	[TOMOYO_CONFIG_LEARNING]   = "learning",
	[TOMOYO_CONFIG_PERMISSIVE] = "permissive",
	[TOMOYO_CONFIG_ENFORCING]  = "enforcing"
20 21
};

T
Tetsuo Handa 已提交
22
/* String table for /sys/kernel/security/tomoyo/profile */
T
Tetsuo Handa 已提交
23
const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
T
Tetsuo Handa 已提交
24
				       + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
T
Tetsuo Handa 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
	[TOMOYO_MAC_FILE_EXECUTE]    = "execute",
	[TOMOYO_MAC_FILE_OPEN]       = "open",
	[TOMOYO_MAC_FILE_CREATE]     = "create",
	[TOMOYO_MAC_FILE_UNLINK]     = "unlink",
	[TOMOYO_MAC_FILE_GETATTR]    = "getattr",
	[TOMOYO_MAC_FILE_MKDIR]      = "mkdir",
	[TOMOYO_MAC_FILE_RMDIR]      = "rmdir",
	[TOMOYO_MAC_FILE_MKFIFO]     = "mkfifo",
	[TOMOYO_MAC_FILE_MKSOCK]     = "mksock",
	[TOMOYO_MAC_FILE_TRUNCATE]   = "truncate",
	[TOMOYO_MAC_FILE_SYMLINK]    = "symlink",
	[TOMOYO_MAC_FILE_MKBLOCK]    = "mkblock",
	[TOMOYO_MAC_FILE_MKCHAR]     = "mkchar",
	[TOMOYO_MAC_FILE_LINK]       = "link",
	[TOMOYO_MAC_FILE_RENAME]     = "rename",
	[TOMOYO_MAC_FILE_CHMOD]      = "chmod",
	[TOMOYO_MAC_FILE_CHOWN]      = "chown",
	[TOMOYO_MAC_FILE_CHGRP]      = "chgrp",
	[TOMOYO_MAC_FILE_IOCTL]      = "ioctl",
	[TOMOYO_MAC_FILE_CHROOT]     = "chroot",
	[TOMOYO_MAC_FILE_MOUNT]      = "mount",
	[TOMOYO_MAC_FILE_UMOUNT]     = "unmount",
	[TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
T
Tetsuo Handa 已提交
48
	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
49 50
};

51 52
/* String table for PREFERENCE keyword. */
static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
T
Tetsuo Handa 已提交
53
	[TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
54 55 56
	[TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
};

T
Tetsuo Handa 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/* String table for path operation. */
const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
	[TOMOYO_TYPE_EXECUTE]    = "execute",
	[TOMOYO_TYPE_READ]       = "read",
	[TOMOYO_TYPE_WRITE]      = "write",
	[TOMOYO_TYPE_APPEND]     = "append",
	[TOMOYO_TYPE_UNLINK]     = "unlink",
	[TOMOYO_TYPE_GETATTR]    = "getattr",
	[TOMOYO_TYPE_RMDIR]      = "rmdir",
	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
	[TOMOYO_TYPE_SYMLINK]    = "symlink",
	[TOMOYO_TYPE_CHROOT]     = "chroot",
	[TOMOYO_TYPE_UMOUNT]     = "unmount",
};

/* String table for categories. */
static const char * const tomoyo_category_keywords
[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
	[TOMOYO_MAC_CATEGORY_FILE]       = "file",
};

78 79 80 81 82
/* Permit policy management by non-root user? */
static bool tomoyo_manage_by_non_root;

/* Utility functions. */

T
Tetsuo Handa 已提交
83 84 85 86 87
/**
 * tomoyo_yesno - Return "yes" or "no".
 *
 * @value: Bool value.
 */
T
Tetsuo Handa 已提交
88
const char *tomoyo_yesno(const unsigned int value)
T
Tetsuo Handa 已提交
89 90 91 92
{
	return value ? "yes" : "no";
}

93 94 95 96 97 98 99 100 101
/**
 * tomoyo_addprintf - strncat()-like-snprintf().
 *
 * @buffer: Buffer to write to. Must be '\0'-terminated.
 * @len:    Size of @buffer.
 * @fmt:    The printf()'s format string, followed by parameters.
 *
 * Returns nothing.
 */
102 103 104 105 106 107 108 109 110
static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
{
	va_list args;
	const int pos = strlen(buffer);
	va_start(args, fmt);
	vsnprintf(buffer + pos, len - pos - 1, fmt, args);
	va_end(args);
}

111
/**
112
 * tomoyo_flush - Flush queued string to userspace's buffer.
113
 *
114
 * @head:   Pointer to "struct tomoyo_io_buffer".
115
 *
116
 * Returns true if all data was flushed, false otherwise.
117
 */
118
static bool tomoyo_flush(struct tomoyo_io_buffer *head)
119
{
120 121
	while (head->r.w_pos) {
		const char *w = head->r.w[0];
T
Tetsuo Handa 已提交
122
		size_t len = strlen(w);
123 124 125 126 127 128 129 130 131 132 133
		if (len) {
			if (len > head->read_user_buf_avail)
				len = head->read_user_buf_avail;
			if (!len)
				return false;
			if (copy_to_user(head->read_user_buf, w, len))
				return false;
			head->read_user_buf_avail -= len;
			head->read_user_buf += len;
			w += len;
		}
134 135
		head->r.w[0] = w;
		if (*w)
136
			return false;
T
Tetsuo Handa 已提交
137
		/* Add '\0' for audit logs and query. */
138 139 140 141 142 143 144 145 146 147 148 149 150
		if (head->poll) {
			if (!head->read_user_buf_avail ||
			    copy_to_user(head->read_user_buf, "", 1))
				return false;
			head->read_user_buf_avail--;
			head->read_user_buf++;
		}
		head->r.w_pos--;
		for (len = 0; len < head->r.w_pos; len++)
			head->r.w[len] = head->r.w[len + 1];
	}
	head->r.avail = 0;
	return true;
151 152
}

153
/**
154
 * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
155
 *
156 157
 * @head:   Pointer to "struct tomoyo_io_buffer".
 * @string: String to print.
158
 *
159 160 161
 * Note that @string has to be kept valid until @head is kfree()d.
 * This means that char[] allocated on stack memory cannot be passed to
 * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
162
 */
163
static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
164
{
165 166 167 168 169
	if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
		head->r.w[head->r.w_pos++] = string;
		tomoyo_flush(head);
	} else
		WARN_ON(1);
170 171
}

172
/**
173
 * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
174 175 176 177
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @fmt:  The printf()'s format string, followed by parameters.
 */
178
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
179 180
{
	va_list args;
T
Tetsuo Handa 已提交
181 182
	size_t len;
	size_t pos = head->r.avail;
183 184
	int size = head->readbuf_size - pos;
	if (size <= 0)
185
		return;
186
	va_start(args, fmt);
187
	len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
188
	va_end(args);
189 190 191 192 193 194 195 196
	if (pos + len >= head->readbuf_size) {
		WARN_ON(1);
		return;
	}
	head->r.avail += len;
	tomoyo_set_string(head, head->read_buf + pos);
}

T
Tetsuo Handa 已提交
197 198 199 200 201 202 203
/**
 * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns nothing.
 */
204 205 206 207 208
static void tomoyo_set_space(struct tomoyo_io_buffer *head)
{
	tomoyo_set_string(head, " ");
}

T
Tetsuo Handa 已提交
209 210 211 212 213 214 215
/**
 * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns nothing.
 */
216 217 218 219 220 221
static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
{
	tomoyo_set_string(head, "\n");
	return !head->r.w_pos;
}

T
Tetsuo Handa 已提交
222 223 224 225 226 227 228 229 230 231 232 233
/**
 * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns nothing.
 */
static void tomoyo_set_slash(struct tomoyo_io_buffer *head)
{
	tomoyo_set_string(head, "/");
}

234 235 236 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 272 273 274 275 276 277
/* List of namespaces. */
LIST_HEAD(tomoyo_namespace_list);
/* True if namespace other than tomoyo_kernel_namespace is defined. */
static bool tomoyo_namespace_enabled;

/**
 * tomoyo_init_policy_namespace - Initialize namespace.
 *
 * @ns: Pointer to "struct tomoyo_policy_namespace".
 *
 * Returns nothing.
 */
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
{
	unsigned int idx;
	for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
		INIT_LIST_HEAD(&ns->acl_group[idx]);
	for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
		INIT_LIST_HEAD(&ns->group_list[idx]);
	for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
		INIT_LIST_HEAD(&ns->policy_list[idx]);
	ns->profile_version = 20100903;
	tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
	list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
}

/**
 * tomoyo_print_namespace - Print namespace header.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns nothing.
 */
static void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
{
	if (!tomoyo_namespace_enabled)
		return;
	tomoyo_set_string(head,
			  container_of(head->r.ns,
				       struct tomoyo_policy_namespace,
				       namespace_list)->name);
	tomoyo_set_space(head);
}

278 279 280 281 282 283 284 285 286 287
/**
 * tomoyo_print_name_union - Print a tomoyo_name_union.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @ptr:  Pointer to "struct tomoyo_name_union".
 */
static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
				    const struct tomoyo_name_union *ptr)
{
	tomoyo_set_space(head);
T
Tetsuo Handa 已提交
288
	if (ptr->group) {
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
		tomoyo_set_string(head, "@");
		tomoyo_set_string(head, ptr->group->group_name->name);
	} else {
		tomoyo_set_string(head, ptr->filename->name);
	}
}

/**
 * tomoyo_print_number_union - Print a tomoyo_number_union.
 *
 * @head:       Pointer to "struct tomoyo_io_buffer".
 * @ptr:        Pointer to "struct tomoyo_number_union".
 */
static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
				      const struct tomoyo_number_union *ptr)
{
	tomoyo_set_space(head);
T
Tetsuo Handa 已提交
306
	if (ptr->group) {
307 308 309 310 311 312
		tomoyo_set_string(head, "@");
		tomoyo_set_string(head, ptr->group->group_name->name);
	} else {
		int i;
		unsigned long min = ptr->values[0];
		const unsigned long max = ptr->values[1];
T
Tetsuo Handa 已提交
313 314
		u8 min_type = ptr->value_type[0];
		const u8 max_type = ptr->value_type[1];
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
		char buffer[128];
		buffer[0] = '\0';
		for (i = 0; i < 2; i++) {
			switch (min_type) {
			case TOMOYO_VALUE_TYPE_HEXADECIMAL:
				tomoyo_addprintf(buffer, sizeof(buffer),
						 "0x%lX", min);
				break;
			case TOMOYO_VALUE_TYPE_OCTAL:
				tomoyo_addprintf(buffer, sizeof(buffer),
						 "0%lo", min);
				break;
			default:
				tomoyo_addprintf(buffer, sizeof(buffer),
						 "%lu", min);
				break;
			}
			if (min == max && min_type == max_type)
				break;
			tomoyo_addprintf(buffer, sizeof(buffer), "-");
			min_type = max_type;
			min = max;
		}
		tomoyo_io_printf(head, "%s", buffer);
	}
340 341 342
}

/**
T
Tetsuo Handa 已提交
343
 * tomoyo_assign_profile - Create a new profile.
344
 *
345
 * @ns:      Pointer to "struct tomoyo_policy_namespace".
346 347 348 349
 * @profile: Profile number to create.
 *
 * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
 */
350 351
static struct tomoyo_profile *tomoyo_assign_profile
(struct tomoyo_policy_namespace *ns, const unsigned int profile)
352
{
T
Tetsuo Handa 已提交
353 354
	struct tomoyo_profile *ptr;
	struct tomoyo_profile *entry;
355 356
	if (profile >= TOMOYO_MAX_PROFILES)
		return NULL;
357
	ptr = ns->profile_ptr[profile];
358
	if (ptr)
T
Tetsuo Handa 已提交
359 360 361 362
		return ptr;
	entry = kzalloc(sizeof(*entry), GFP_NOFS);
	if (mutex_lock_interruptible(&tomoyo_policy_lock))
		goto out;
363
	ptr = ns->profile_ptr[profile];
T
Tetsuo Handa 已提交
364 365
	if (!ptr && tomoyo_memory_ok(entry)) {
		ptr = entry;
T
Tetsuo Handa 已提交
366 367 368
		ptr->default_config = TOMOYO_CONFIG_DISABLED |
			TOMOYO_CONFIG_WANT_GRANT_LOG |
			TOMOYO_CONFIG_WANT_REJECT_LOG;
T
Tetsuo Handa 已提交
369 370
		memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
		       sizeof(ptr->config));
T
Tetsuo Handa 已提交
371
		ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024;
372
		ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048;
T
Tetsuo Handa 已提交
373
		mb(); /* Avoid out-of-order execution. */
374
		ns->profile_ptr[profile] = ptr;
T
Tetsuo Handa 已提交
375
		entry = NULL;
376
	}
377
	mutex_unlock(&tomoyo_policy_lock);
T
Tetsuo Handa 已提交
378 379
 out:
	kfree(entry);
380 381 382 383
	return ptr;
}

/**
T
Tetsuo Handa 已提交
384 385
 * tomoyo_profile - Find a profile.
 *
386
 * @ns:      Pointer to "struct tomoyo_policy_namespace".
T
Tetsuo Handa 已提交
387 388 389 390
 * @profile: Profile number to find.
 *
 * Returns pointer to "struct tomoyo_profile".
 */
391 392
struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
				      const u8 profile)
T
Tetsuo Handa 已提交
393
{
394
	static struct tomoyo_profile tomoyo_null_profile;
395
	struct tomoyo_profile *ptr = ns->profile_ptr[profile];
396 397
	if (!ptr)
		ptr = &tomoyo_null_profile;
T
Tetsuo Handa 已提交
398 399 400
	return ptr;
}

401 402 403 404 405 406 407 408
/**
 * tomoyo_find_yesno - Find values for specified keyword.
 *
 * @string: String to check.
 * @find:   Name of keyword.
 *
 * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
 */
T
Tetsuo Handa 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421
static s8 tomoyo_find_yesno(const char *string, const char *find)
{
	const char *cp = strstr(string, find);
	if (cp) {
		cp += strlen(find);
		if (!strncmp(cp, "=yes", 4))
			return 1;
		else if (!strncmp(cp, "=no", 3))
			return 0;
	}
	return -1;
}

422 423 424 425 426 427 428 429 430
/**
 * tomoyo_set_uint - Set value for specified preference.
 *
 * @i:      Pointer to "unsigned int".
 * @string: String to check.
 * @find:   Name of keyword.
 *
 * Returns nothing.
 */
T
Tetsuo Handa 已提交
431 432 433 434 435 436 437 438
static void tomoyo_set_uint(unsigned int *i, const char *string,
			    const char *find)
{
	const char *cp = strstr(string, find);
	if (cp)
		sscanf(cp + strlen(find), "=%u", i);
}

439 440 441 442 443 444 445 446 447
/**
 * tomoyo_set_mode - Set mode for specified profile.
 *
 * @name:    Name of functionality.
 * @value:   Mode for @name.
 * @profile: Pointer to "struct tomoyo_profile".
 *
 * Returns 0 on success, negative value otherwise.
 */
T
Tetsuo Handa 已提交
448 449 450 451 452 453 454 455 456 457 458 459
static int tomoyo_set_mode(char *name, const char *value,
			   struct tomoyo_profile *profile)
{
	u8 i;
	u8 config;
	if (!strcmp(name, "CONFIG")) {
		i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
		config = profile->default_config;
	} else if (tomoyo_str_starts(&name, "CONFIG::")) {
		config = 0;
		for (i = 0; i < TOMOYO_MAX_MAC_INDEX
			     + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
T
Tetsuo Handa 已提交
460 461 462 463 464 465 466 467 468 469 470
			int len = 0;
			if (i < TOMOYO_MAX_MAC_INDEX) {
				const u8 c = tomoyo_index2category[i];
				const char *category =
					tomoyo_category_keywords[c];
				len = strlen(category);
				if (strncmp(name, category, len) ||
				    name[len++] != ':' || name[len++] != ':')
					continue;
			}
			if (strcmp(name + len, tomoyo_mac_keywords[i]))
T
Tetsuo Handa 已提交
471 472 473 474 475 476 477 478 479
				continue;
			config = profile->config[i];
			break;
		}
		if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
			return -EINVAL;
	} else {
		return -EINVAL;
	}
480
	if (strstr(value, "use_default")) {
T
Tetsuo Handa 已提交
481 482 483 484 485 486 487 488 489 490
		config = TOMOYO_CONFIG_USE_DEFAULT;
	} else {
		u8 mode;
		for (mode = 0; mode < 4; mode++)
			if (strstr(value, tomoyo_mode[mode]))
				/*
				 * Update lower 3 bits in order to distinguish
				 * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
				 */
				config = (config & ~7) | mode;
T
Tetsuo Handa 已提交
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
		if (config != TOMOYO_CONFIG_USE_DEFAULT) {
			switch (tomoyo_find_yesno(value, "grant_log")) {
			case 1:
				config |= TOMOYO_CONFIG_WANT_GRANT_LOG;
				break;
			case 0:
				config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG;
				break;
			}
			switch (tomoyo_find_yesno(value, "reject_log")) {
			case 1:
				config |= TOMOYO_CONFIG_WANT_REJECT_LOG;
				break;
			case 0:
				config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG;
				break;
			}
		}
T
Tetsuo Handa 已提交
509 510 511 512 513 514 515 516
	}
	if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
		profile->config[i] = config;
	else if (config != TOMOYO_CONFIG_USE_DEFAULT)
		profile->default_config = config;
	return 0;
}

T
Tetsuo Handa 已提交
517 518
/**
 * tomoyo_write_profile - Write profile table.
519 520 521 522 523 524 525 526 527 528 529
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
{
	char *data = head->write_buf;
	unsigned int i;
	char *cp;
	struct tomoyo_profile *profile;
530 531
	if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
	    == 1)
T
Tetsuo Handa 已提交
532 533
		return 0;
	i = simple_strtoul(data, &cp, 10);
534 535 536
	if (*cp != '-')
		return -EINVAL;
	data = cp + 1;
537
	profile = tomoyo_assign_profile(head->w.ns, i);
538 539
	if (!profile)
		return -EINVAL;
540 541 542
	cp = strchr(data, '=');
	if (!cp)
		return -EINVAL;
T
Tetsuo Handa 已提交
543
	*cp++ = '\0';
544
	if (!strcmp(data, "COMMENT")) {
545 546 547 548 549 550 551 552 553 554
		static DEFINE_SPINLOCK(lock);
		const struct tomoyo_path_info *new_comment
			= tomoyo_get_name(cp);
		const struct tomoyo_path_info *old_comment;
		if (!new_comment)
			return -ENOMEM;
		spin_lock(&lock);
		old_comment = profile->comment;
		profile->comment = new_comment;
		spin_unlock(&lock);
555
		tomoyo_put_name(old_comment);
556 557
		return 0;
	}
558 559 560 561 562
	if (!strcmp(data, "PREFERENCE")) {
		for (i = 0; i < TOMOYO_MAX_PREF; i++)
			tomoyo_set_uint(&profile->pref[i], cp,
					tomoyo_pref_keywords[i]);
		return 0;
563
	}
564
	return tomoyo_set_mode(data, cp, profile);
565 566
}

T
Tetsuo Handa 已提交
567 568 569 570 571 572 573 574 575 576
/**
 * tomoyo_print_config - Print mode for specified functionality.
 *
 * @head:   Pointer to "struct tomoyo_io_buffer".
 * @config: Mode for that functionality.
 *
 * Returns nothing.
 *
 * Caller prints functionality's name.
 */
577 578
static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
{
T
Tetsuo Handa 已提交
579 580 581 582
	tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
			 tomoyo_mode[config & 3],
			 tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG),
			 tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG));
583 584
}

585
/**
T
Tetsuo Handa 已提交
586
 * tomoyo_read_profile - Read profile table.
587 588
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
T
Tetsuo Handa 已提交
589 590
 *
 * Returns nothing.
591
 */
592
static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
593
{
594
	u8 index;
595 596
	struct tomoyo_policy_namespace *ns =
		container_of(head->r.ns, typeof(*ns), namespace_list);
597
	const struct tomoyo_profile *profile;
598 599
	if (head->r.eof)
		return;
600 601
 next:
	index = head->r.index;
602
	profile = ns->profile_ptr[index];
603 604
	switch (head->r.step) {
	case 0:
605 606 607
		tomoyo_print_namespace(head);
		tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
				 ns->profile_version);
608 609 610 611 612
		head->r.step++;
		break;
	case 1:
		for ( ; head->r.index < TOMOYO_MAX_PROFILES;
		      head->r.index++)
613
			if (ns->profile_ptr[head->r.index])
614 615 616 617 618 619 620
				break;
		if (head->r.index == TOMOYO_MAX_PROFILES)
			return;
		head->r.step++;
		break;
	case 2:
		{
621
			u8 i;
622 623
			const struct tomoyo_path_info *comment =
				profile->comment;
624
			tomoyo_print_namespace(head);
625 626 627
			tomoyo_io_printf(head, "%u-COMMENT=", index);
			tomoyo_set_string(head, comment ? comment->name : "");
			tomoyo_set_lf(head);
628 629 630 631 632 633
			tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
			for (i = 0; i < TOMOYO_MAX_PREF; i++)
				tomoyo_io_printf(head, "%s=%u ",
						 tomoyo_pref_keywords[i],
						 profile->pref[i]);
			tomoyo_set_string(head, "}\n");
634 635 636 637 638
			head->r.step++;
		}
		break;
	case 3:
		{
639
			tomoyo_print_namespace(head);
640 641 642 643 644 645 646 647 648 649 650
			tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
			tomoyo_print_config(head, profile->default_config);
			head->r.bit = 0;
			head->r.step++;
		}
		break;
	case 4:
		for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
			      + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
			const u8 i = head->r.bit;
			const u8 config = profile->config[i];
T
Tetsuo Handa 已提交
651 652
			if (config == TOMOYO_CONFIG_USE_DEFAULT)
				continue;
653
			tomoyo_print_namespace(head);
T
Tetsuo Handa 已提交
654 655 656 657 658 659 660 661 662
			if (i < TOMOYO_MAX_MAC_INDEX)
				tomoyo_io_printf(head, "%u-CONFIG::%s::%s",
						 index,
						 tomoyo_category_keywords
						 [tomoyo_index2category[i]],
						 tomoyo_mac_keywords[i]);
			else
				tomoyo_io_printf(head, "%u-CONFIG::%s", index,
						 tomoyo_mac_keywords[i]);
663 664 665 666 667 668 669 670
			tomoyo_print_config(head, config);
			head->r.bit++;
			break;
		}
		if (head->r.bit == TOMOYO_MAX_MAC_INDEX
		    + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
			head->r.index++;
			head->r.step = 1;
671
		}
T
Tetsuo Handa 已提交
672
		break;
673
	}
674 675
	if (tomoyo_flush(head))
		goto next;
676 677
}

T
Tetsuo Handa 已提交
678 679
static bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
				const struct tomoyo_acl_head *b)
680
{
T
Tetsuo Handa 已提交
681 682
	return container_of(a, struct tomoyo_manager, head)->manager ==
		container_of(b, struct tomoyo_manager, head)->manager;
683 684
}

685 686 687 688 689 690 691
/**
 * tomoyo_update_manager_entry - Add a manager entry.
 *
 * @manager:   The path to manager or the domainnamme.
 * @is_delete: True if it is a delete request.
 *
 * Returns 0 on success, negative value otherwise.
692 693
 *
 * Caller holds tomoyo_read_lock().
694 695 696 697
 */
static int tomoyo_update_manager_entry(const char *manager,
				       const bool is_delete)
{
T
Tetsuo Handa 已提交
698
	struct tomoyo_manager e = { };
699
	struct tomoyo_acl_param param = {
700
		/* .ns = &tomoyo_kernel_namespace, */
701
		.is_delete = is_delete,
702 703
		.list = &tomoyo_kernel_namespace.
		policy_list[TOMOYO_ID_MANAGER],
704 705
	};
	int error = is_delete ? -ENOENT : -ENOMEM;
T
Tetsuo Handa 已提交
706 707
	if (tomoyo_domain_def(manager)) {
		if (!tomoyo_correct_domain(manager))
708
			return -EINVAL;
709
		e.is_domain = true;
710
	} else {
T
Tetsuo Handa 已提交
711
		if (!tomoyo_correct_path(manager))
712 713
			return -EINVAL;
	}
714
	e.manager = tomoyo_get_name(manager);
715 716 717 718 719
	if (e.manager) {
		error = tomoyo_update_policy(&e.head, sizeof(e), &param,
					     tomoyo_same_manager);
		tomoyo_put_name(e.manager);
	}
720 721 722 723
	return error;
}

/**
T
Tetsuo Handa 已提交
724
 * tomoyo_write_manager - Write manager policy.
725 726 727 728
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0 on success, negative value otherwise.
729 730
 *
 * Caller holds tomoyo_read_lock().
731
 */
T
Tetsuo Handa 已提交
732
static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
733 734 735 736
{
	char *data = head->write_buf;

	if (!strcmp(data, "manage_by_non_root")) {
737
		tomoyo_manage_by_non_root = !head->w.is_delete;
738 739
		return 0;
	}
740
	return tomoyo_update_manager_entry(data, head->w.is_delete);
741 742 743
}

/**
T
Tetsuo Handa 已提交
744
 * tomoyo_read_manager - Read manager policy.
745 746 747
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
748
 * Caller holds tomoyo_read_lock().
749
 */
T
Tetsuo Handa 已提交
750
static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
751
{
752
	if (head->r.eof)
753
		return;
754 755
	list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.
			     policy_list[TOMOYO_ID_MANAGER]) {
T
Tetsuo Handa 已提交
756
		struct tomoyo_manager *ptr =
757
			list_entry(head->r.acl, typeof(*ptr), head.list);
758
		if (ptr->head.is_deleted)
759
			continue;
760 761 762 763
		if (!tomoyo_flush(head))
			return;
		tomoyo_set_string(head, ptr->manager->name);
		tomoyo_set_lf(head);
764
	}
765
	head->r.eof = true;
766 767 768
}

/**
T
Tetsuo Handa 已提交
769
 * tomoyo_manager - Check whether the current process is a policy manager.
770 771 772
 *
 * Returns true if the current process is permitted to modify policy
 * via /sys/kernel/security/tomoyo/ interface.
773 774
 *
 * Caller holds tomoyo_read_lock().
775
 */
T
Tetsuo Handa 已提交
776
static bool tomoyo_manager(void)
777
{
T
Tetsuo Handa 已提交
778
	struct tomoyo_manager *ptr;
779 780 781 782 783 784 785 786 787
	const char *exe;
	const struct task_struct *task = current;
	const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
	bool found = false;

	if (!tomoyo_policy_loaded)
		return true;
	if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
		return false;
788 789
	list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
				policy_list[TOMOYO_ID_MANAGER], head.list) {
790
		if (!ptr->head.is_deleted && ptr->is_domain
791 792 793 794 795 796 797 798 799 800
		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
			found = true;
			break;
		}
	}
	if (found)
		return true;
	exe = tomoyo_get_exe();
	if (!exe)
		return false;
801 802
	list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
				policy_list[TOMOYO_ID_MANAGER], head.list) {
803
		if (!ptr->head.is_deleted && !ptr->is_domain
804 805 806 807 808 809 810 811 812 813 814 815 816 817
		    && !strcmp(exe, ptr->manager->name)) {
			found = true;
			break;
		}
	}
	if (!found) { /* Reduce error messages. */
		static pid_t last_pid;
		const pid_t pid = current->pid;
		if (last_pid != pid) {
			printk(KERN_WARNING "%s ( %s ) is not permitted to "
			       "update policies.\n", domainname->name, exe);
			last_pid = pid;
		}
	}
818
	kfree(exe);
819 820 821 822
	return found;
}

/**
823
 * tomoyo_select_domain - Parse select command.
824 825 826 827 828
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @data: String to parse.
 *
 * Returns true on success, false otherwise.
829 830
 *
 * Caller holds tomoyo_read_lock().
831
 */
832 833
static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
				 const char *data)
834 835 836
{
	unsigned int pid;
	struct tomoyo_domain_info *domain = NULL;
837
	bool global_pid = false;
838 839 840
	if (strncmp(data, "select ", 7))
		return false;
	data += 7;
841 842
	if (sscanf(data, "pid=%u", &pid) == 1 ||
	    (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
843
		struct task_struct *p;
844
		rcu_read_lock();
845
		read_lock(&tasklist_lock);
846 847 848 849
		if (global_pid)
			p = find_task_by_pid_ns(pid, &init_pid_ns);
		else
			p = find_task_by_vpid(pid);
850 851 852
		if (p)
			domain = tomoyo_real_domain(p);
		read_unlock(&tasklist_lock);
853
		rcu_read_unlock();
854
	} else if (!strncmp(data, "domain=", 7)) {
T
Tetsuo Handa 已提交
855
		if (tomoyo_domain_def(data + 7))
856 857 858
			domain = tomoyo_find_domain(data + 7);
	} else
		return false;
T
Tetsuo Handa 已提交
859
	head->w.domain = domain;
860 861 862
	/* Accessing read_buf is safe because head->io_sem is held. */
	if (!head->read_buf)
		return true; /* Do nothing if open(O_WRONLY). */
863 864
	memset(&head->r, 0, sizeof(head->r));
	head->r.print_this_domain_only = true;
865 866 867 868
	if (domain)
		head->r.domain = &domain->list;
	else
		head->r.eof = 1;
869
	tomoyo_io_printf(head, "# select %s\n", data);
T
Tetsuo Handa 已提交
870 871
	if (domain && domain->is_deleted)
		tomoyo_io_printf(head, "# This is a deleted domain.\n");
872 873 874
	return true;
}

875 876 877 878 879 880
/**
 * tomoyo_delete_domain - Delete a domain.
 *
 * @domainname: The name of domain.
 *
 * Returns 0.
881 882
 *
 * Caller holds tomoyo_read_lock().
883 884 885 886 887 888 889 890
 */
static int tomoyo_delete_domain(char *domainname)
{
	struct tomoyo_domain_info *domain;
	struct tomoyo_path_info name;

	name.name = domainname;
	tomoyo_fill_path_info(&name);
891 892
	if (mutex_lock_interruptible(&tomoyo_policy_lock))
		return 0;
893
	/* Is there an active domain? */
894
	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
895 896 897 898 899 900 901 902 903
		/* Never delete tomoyo_kernel_domain */
		if (domain == &tomoyo_kernel_domain)
			continue;
		if (domain->is_deleted ||
		    tomoyo_pathcmp(domain->domainname, &name))
			continue;
		domain->is_deleted = true;
		break;
	}
904
	mutex_unlock(&tomoyo_policy_lock);
905 906 907
	return 0;
}

908
/**
T
Tetsuo Handa 已提交
909
 * tomoyo_write_domain2 - Write domain policy.
910
 *
911
 * @ns:        Pointer to "struct tomoyo_policy_namespace".
912 913 914
 * @list:      Pointer to "struct list_head".
 * @data:      Policy to be interpreted.
 * @is_delete: True if it is a delete request.
915 916 917 918 919
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
920 921
static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
				struct list_head *list, char *data,
T
Tetsuo Handa 已提交
922
				const bool is_delete)
923
{
924
	struct tomoyo_acl_param param = {
925
		.ns = ns,
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
		.list = list,
		.data = data,
		.is_delete = is_delete,
	};
	static const struct {
		const char *keyword;
		int (*write) (struct tomoyo_acl_param *);
	} tomoyo_callback[1] = {
		{ "file ", tomoyo_write_file },
	};
	u8 i;
	for (i = 0; i < 1; i++) {
		if (!tomoyo_str_starts(&param.data,
				       tomoyo_callback[i].keyword))
			continue;
		return tomoyo_callback[i].write(&param);
	}
	return -EINVAL;
944 945
}

T
Tetsuo Handa 已提交
946 947 948 949 950 951
/* String table for domain flags. */
const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = {
	[TOMOYO_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
	[TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n",
};

952
/**
T
Tetsuo Handa 已提交
953
 * tomoyo_write_domain - Write domain policy.
954 955 956 957
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0 on success, negative value otherwise.
958 959
 *
 * Caller holds tomoyo_read_lock().
960
 */
T
Tetsuo Handa 已提交
961
static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
962 963
{
	char *data = head->write_buf;
964
	struct tomoyo_policy_namespace *ns;
T
Tetsuo Handa 已提交
965
	struct tomoyo_domain_info *domain = head->w.domain;
966 967
	const bool is_delete = head->w.is_delete;
	bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
968
	unsigned int profile;
969
	if (*data == '<') {
970 971 972
		domain = NULL;
		if (is_delete)
			tomoyo_delete_domain(data);
973
		else if (is_select)
974
			domain = tomoyo_find_domain(data);
975
		else
976
			domain = tomoyo_assign_domain(data, false);
T
Tetsuo Handa 已提交
977
		head->w.domain = domain;
978 979 980 981
		return 0;
	}
	if (!domain)
		return -EINVAL;
982
	ns = domain->ns;
T
Tetsuo Handa 已提交
983
	if (sscanf(data, "use_profile %u", &profile) == 1
984
	    && profile < TOMOYO_MAX_PROFILES) {
985
		if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
986 987 988
			domain->profile = (u8) profile;
		return 0;
	}
T
Tetsuo Handa 已提交
989 990 991 992 993 994
	if (sscanf(data, "use_group %u\n", &profile) == 1
	    && profile < TOMOYO_MAX_ACL_GROUPS) {
		if (!is_delete)
			domain->group = (u8) profile;
		return 0;
	}
T
Tetsuo Handa 已提交
995 996 997 998 999
	for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) {
		const char *cp = tomoyo_dif[profile];
		if (strncmp(data, cp, strlen(cp) - 1))
			continue;
		domain->flags[profile] = !is_delete;
1000 1001
		return 0;
	}
1002 1003
	return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
				    is_delete);
1004 1005 1006
}

/**
T
Tetsuo Handa 已提交
1007
 * tomoyo_set_group - Print "acl_group " header keyword and category name.
1008
 *
T
Tetsuo Handa 已提交
1009 1010
 * @head:     Pointer to "struct tomoyo_io_buffer".
 * @category: Category name.
1011
 *
T
Tetsuo Handa 已提交
1012
 * Returns nothing.
1013
 */
T
Tetsuo Handa 已提交
1014 1015
static void tomoyo_set_group(struct tomoyo_io_buffer *head,
			     const char *category)
1016
{
1017 1018
	if (head->type == TOMOYO_EXCEPTIONPOLICY) {
		tomoyo_print_namespace(head);
T
Tetsuo Handa 已提交
1019 1020
		tomoyo_io_printf(head, "acl_group %u ",
				 head->r.acl_group_index);
1021
	}
T
Tetsuo Handa 已提交
1022
	tomoyo_set_string(head, category);
1023 1024 1025
}

/**
1026
 * tomoyo_print_entry - Print an ACL entry.
1027 1028
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
1029
 * @acl:  Pointer to an ACL entry.
1030 1031 1032
 *
 * Returns true on success, false otherwise.
 */
1033 1034
static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
			       struct tomoyo_acl_info *acl)
1035
{
1036
	const u8 acl_type = acl->type;
T
Tetsuo Handa 已提交
1037
	bool first = true;
1038
	u8 bit;
1039

1040 1041
	if (acl->is_deleted)
		return true;
1042 1043 1044
	if (!tomoyo_flush(head))
		return false;
	else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
1045 1046 1047
		struct tomoyo_path_acl *ptr =
			container_of(acl, typeof(*ptr), head);
		const u16 perm = ptr->perm;
T
Tetsuo Handa 已提交
1048
		for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
1049 1050
			if (!(perm & (1 << bit)))
				continue;
1051
			if (head->r.print_transition_related_only &&
1052 1053
			    bit != TOMOYO_TYPE_EXECUTE)
				continue;
T
Tetsuo Handa 已提交
1054 1055 1056 1057 1058 1059 1060
			if (first) {
				tomoyo_set_group(head, "file ");
				first = false;
			} else {
				tomoyo_set_slash(head);
			}
			tomoyo_set_string(head, tomoyo_path_keyword[bit]);
1061
		}
T
Tetsuo Handa 已提交
1062 1063
		if (first)
			return true;
1064
		tomoyo_print_name_union(head, &ptr->name);
1065
	} else if (head->r.print_transition_related_only) {
1066 1067 1068 1069
		return true;
	} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
		struct tomoyo_path2_acl *ptr =
			container_of(acl, typeof(*ptr), head);
T
Tetsuo Handa 已提交
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
		const u8 perm = ptr->perm;
		for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
			if (!(perm & (1 << bit)))
				continue;
			if (first) {
				tomoyo_set_group(head, "file ");
				first = false;
			} else {
				tomoyo_set_slash(head);
			}
			tomoyo_set_string(head, tomoyo_mac_keywords
					  [tomoyo_pp2mac[bit]]);
		}
		if (first)
			return true;
1085 1086
		tomoyo_print_name_union(head, &ptr->name1);
		tomoyo_print_name_union(head, &ptr->name2);
1087 1088 1089
	} else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
		struct tomoyo_path_number_acl *ptr =
			container_of(acl, typeof(*ptr), head);
T
Tetsuo Handa 已提交
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
		const u8 perm = ptr->perm;
		for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) {
			if (!(perm & (1 << bit)))
				continue;
			if (first) {
				tomoyo_set_group(head, "file ");
				first = false;
			} else {
				tomoyo_set_slash(head);
			}
			tomoyo_set_string(head, tomoyo_mac_keywords
					  [tomoyo_pn2mac[bit]]);
		}
		if (first)
			return true;
1105 1106
		tomoyo_print_name_union(head, &ptr->name);
		tomoyo_print_number_union(head, &ptr->number);
1107 1108 1109
	} else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
		struct tomoyo_mkdev_acl *ptr =
			container_of(acl, typeof(*ptr), head);
T
Tetsuo Handa 已提交
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
		const u8 perm = ptr->perm;
		for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) {
			if (!(perm & (1 << bit)))
				continue;
			if (first) {
				tomoyo_set_group(head, "file ");
				first = false;
			} else {
				tomoyo_set_slash(head);
			}
			tomoyo_set_string(head, tomoyo_mac_keywords
					  [tomoyo_pnnn2mac[bit]]);
		}
		if (first)
			return true;
1125 1126 1127 1128
		tomoyo_print_name_union(head, &ptr->name);
		tomoyo_print_number_union(head, &ptr->mode);
		tomoyo_print_number_union(head, &ptr->major);
		tomoyo_print_number_union(head, &ptr->minor);
1129 1130 1131
	} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
		struct tomoyo_mount_acl *ptr =
			container_of(acl, typeof(*ptr), head);
T
Tetsuo Handa 已提交
1132
		tomoyo_set_group(head, "file mount");
1133 1134 1135 1136
		tomoyo_print_name_union(head, &ptr->dev_name);
		tomoyo_print_name_union(head, &ptr->dir_name);
		tomoyo_print_name_union(head, &ptr->fs_type);
		tomoyo_print_number_union(head, &ptr->flags);
1137
	}
T
Tetsuo Handa 已提交
1138
	tomoyo_set_lf(head);
1139 1140 1141 1142 1143 1144
	return true;
}

/**
 * tomoyo_read_domain2 - Read domain policy.
 *
T
Tetsuo Handa 已提交
1145 1146
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @list: Pointer to "struct list_head".
1147 1148 1149 1150 1151 1152
 *
 * Caller holds tomoyo_read_lock().
 *
 * Returns true on success, false otherwise.
 */
static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
T
Tetsuo Handa 已提交
1153
				struct list_head *list)
1154
{
T
Tetsuo Handa 已提交
1155
	list_for_each_cookie(head->r.acl, list) {
1156 1157 1158 1159 1160 1161
		struct tomoyo_acl_info *ptr =
			list_entry(head->r.acl, typeof(*ptr), list);
		if (!tomoyo_print_entry(head, ptr))
			return false;
	}
	head->r.acl = NULL;
1162 1163 1164
	return true;
}

1165
/**
T
Tetsuo Handa 已提交
1166
 * tomoyo_read_domain - Read domain policy.
1167 1168 1169
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
1170
 * Caller holds tomoyo_read_lock().
1171
 */
T
Tetsuo Handa 已提交
1172
static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
1173
{
1174
	if (head->r.eof)
1175
		return;
1176
	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
T
Tetsuo Handa 已提交
1177
		struct tomoyo_domain_info *domain =
1178 1179
			list_entry(head->r.domain, typeof(*domain), list);
		switch (head->r.step) {
T
Tetsuo Handa 已提交
1180
			u8 i;
1181 1182 1183 1184 1185 1186 1187
		case 0:
			if (domain->is_deleted &&
			    !head->r.print_this_domain_only)
				continue;
			/* Print domainname and flags. */
			tomoyo_set_string(head, domain->domainname->name);
			tomoyo_set_lf(head);
T
Tetsuo Handa 已提交
1188
			tomoyo_io_printf(head, "use_profile %u\n",
1189
					 domain->profile);
T
Tetsuo Handa 已提交
1190 1191
			tomoyo_io_printf(head, "use_group %u\n",
					 domain->group);
T
Tetsuo Handa 已提交
1192 1193 1194
			for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
				if (domain->flags[i])
					tomoyo_set_string(head, tomoyo_dif[i]);
1195 1196 1197 1198
			head->r.step++;
			tomoyo_set_lf(head);
			/* fall through */
		case 1:
T
Tetsuo Handa 已提交
1199
			if (!tomoyo_read_domain2(head, &domain->acl_info_list))
1200 1201 1202 1203 1204 1205 1206 1207 1208
				return;
			head->r.step++;
			if (!tomoyo_set_lf(head))
				return;
			/* fall through */
		case 2:
			head->r.step = 0;
			if (head->r.print_this_domain_only)
				goto done;
1209 1210
		}
	}
1211 1212
 done:
	head->r.eof = true;
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
}

/**
 * tomoyo_write_domain_profile - Assign profile for specified domain.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0 on success, -EINVAL otherwise.
 *
 * This is equivalent to doing
 *
 *     ( echo "select " $domainname; echo "use_profile " $profile ) |
1225
 *     /usr/sbin/tomoyo-loadpolicy -d
1226 1227
 *
 * Caller holds tomoyo_read_lock().
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
 */
static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
{
	char *data = head->write_buf;
	char *cp = strchr(data, ' ');
	struct tomoyo_domain_info *domain;
	unsigned long profile;

	if (!cp)
		return -EINVAL;
	*cp = '\0';
	domain = tomoyo_find_domain(cp + 1);
	if (strict_strtoul(data, 10, &profile))
		return -EINVAL;
1242 1243
	if (domain && (!tomoyo_policy_loaded ||
		       head->w.ns->profile_ptr[(u8) profile]))
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
		domain->profile = (u8) profile;
	return 0;
}

/**
 * tomoyo_read_domain_profile - Read only domainname and profile.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns list of profile number and domainname pairs.
 *
 * This is equivalent to doing
 *
 *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
 *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
 *     domainname = $0; } else if ( $1 == "use_profile" ) {
 *     print $2 " " domainname; domainname = ""; } } ; '
1261 1262
 *
 * Caller holds tomoyo_read_lock().
1263
 */
1264
static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
1265
{
1266
	if (head->r.eof)
1267
		return;
1268
	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
T
Tetsuo Handa 已提交
1269
		struct tomoyo_domain_info *domain =
1270
			list_entry(head->r.domain, typeof(*domain), list);
1271 1272
		if (domain->is_deleted)
			continue;
1273 1274 1275 1276 1277
		if (!tomoyo_flush(head))
			return;
		tomoyo_io_printf(head, "%u ", domain->profile);
		tomoyo_set_string(head, domain->domainname->name);
		tomoyo_set_lf(head);
1278
	}
1279
	head->r.eof = true;
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
}

/**
 * tomoyo_write_pid: Specify PID to obtain domainname.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0.
 */
static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
{
1291
	head->r.eof = false;
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
	return 0;
}

/**
 * tomoyo_read_pid - Get domainname of the specified PID.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns the domainname which the specified PID is in on success,
 * empty string otherwise.
 * The PID is specified by tomoyo_write_pid() so that the user can obtain
 * using read()/write() interface rather than sysctl() interface.
 */
1305
static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
1306
{
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
	char *buf = head->write_buf;
	bool global_pid = false;
	unsigned int pid;
	struct task_struct *p;
	struct tomoyo_domain_info *domain = NULL;

	/* Accessing write_buf is safe because head->io_sem is held. */
	if (!buf) {
		head->r.eof = true;
		return; /* Do nothing if open(O_RDONLY). */
1317
	}
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
	if (head->r.w_pos || head->r.eof)
		return;
	head->r.eof = true;
	if (tomoyo_str_starts(&buf, "global-pid "))
		global_pid = true;
	pid = (unsigned int) simple_strtoul(buf, NULL, 10);
	rcu_read_lock();
	read_lock(&tasklist_lock);
	if (global_pid)
		p = find_task_by_pid_ns(pid, &init_pid_ns);
	else
		p = find_task_by_vpid(pid);
	if (p)
		domain = tomoyo_real_domain(p);
	read_unlock(&tasklist_lock);
	rcu_read_unlock();
	if (!domain)
		return;
	tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
	tomoyo_set_string(head, domain->domainname->name);
1338 1339
}

1340
static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
1341 1342 1343 1344 1345 1346
	[TOMOYO_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
	[TOMOYO_TRANSITION_CONTROL_RESET]         = "reset_domain ",
	[TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
	[TOMOYO_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
	[TOMOYO_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
	[TOMOYO_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
1347 1348
};

T
Tetsuo Handa 已提交
1349
static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
T
Tetsuo Handa 已提交
1350 1351
	[TOMOYO_PATH_GROUP]   = "path_group ",
	[TOMOYO_NUMBER_GROUP] = "number_group ",
T
Tetsuo Handa 已提交
1352 1353
};

1354
/**
T
Tetsuo Handa 已提交
1355
 * tomoyo_write_exception - Write exception policy.
1356 1357 1358 1359
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0 on success, negative value otherwise.
1360 1361
 *
 * Caller holds tomoyo_read_lock().
1362
 */
T
Tetsuo Handa 已提交
1363
static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
1364
{
1365
	const bool is_delete = head->w.is_delete;
1366
	struct tomoyo_acl_param param = {
1367 1368
		.ns = head->w.ns,
		.is_delete = is_delete,
1369
		.data = head->write_buf,
T
Tetsuo Handa 已提交
1370
	};
1371 1372 1373
	u8 i;
	if (tomoyo_str_starts(&param.data, "aggregator "))
		return tomoyo_write_aggregator(&param);
T
Tetsuo Handa 已提交
1374
	for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
1375 1376
		if (tomoyo_str_starts(&param.data, tomoyo_transition_type[i]))
			return tomoyo_write_transition_control(&param, i);
T
Tetsuo Handa 已提交
1377
	for (i = 0; i < TOMOYO_MAX_GROUP; i++)
1378 1379
		if (tomoyo_str_starts(&param.data, tomoyo_group_name[i]))
			return tomoyo_write_group(&param, i);
T
Tetsuo Handa 已提交
1380 1381 1382 1383 1384
	if (tomoyo_str_starts(&param.data, "acl_group ")) {
		unsigned int group;
		char *data;
		group = simple_strtoul(param.data, &data, 10);
		if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
1385 1386 1387
			return tomoyo_write_domain2
				(head->w.ns, &head->w.ns->acl_group[group],
				 data, is_delete);
T
Tetsuo Handa 已提交
1388
	}
1389 1390 1391 1392
	return -EINVAL;
}

/**
1393
 * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
1394 1395
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
1396 1397 1398
 * @idx:  Index number.
 *
 * Returns true on success, false otherwise.
1399
 *
1400
 * Caller holds tomoyo_read_lock().
1401
 */
1402
static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
1403
{
1404 1405 1406 1407
	struct tomoyo_policy_namespace *ns =
		container_of(head->r.ns, typeof(*ns), namespace_list);
	struct list_head *list = &ns->group_list[idx];
	list_for_each_cookie(head->r.group, list) {
1408
		struct tomoyo_group *group =
T
Tetsuo Handa 已提交
1409
			list_entry(head->r.group, typeof(*group), head.list);
1410
		list_for_each_cookie(head->r.acl, &group->member_list) {
1411
			struct tomoyo_acl_head *ptr =
1412
				list_entry(head->r.acl, typeof(*ptr), list);
1413 1414
			if (ptr->is_deleted)
				continue;
1415 1416
			if (!tomoyo_flush(head))
				return false;
1417
			tomoyo_print_namespace(head);
1418 1419
			tomoyo_set_string(head, tomoyo_group_name[idx]);
			tomoyo_set_string(head, group->group_name->name);
1420
			if (idx == TOMOYO_PATH_GROUP) {
1421 1422 1423 1424
				tomoyo_set_space(head);
				tomoyo_set_string(head, container_of
					       (ptr, struct tomoyo_path_group,
						head)->member_name->name);
1425
			} else if (idx == TOMOYO_NUMBER_GROUP) {
1426 1427 1428 1429
				tomoyo_print_number_union(head, &container_of
							  (ptr,
						   struct tomoyo_number_group,
							   head)->number);
1430
			}
1431
			tomoyo_set_lf(head);
1432
		}
1433
		head->r.acl = NULL;
1434
	}
1435
	head->r.group = NULL;
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
	return true;
}

/**
 * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 * @idx:  Index number.
 *
 * Returns true on success, false otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
{
1451 1452 1453 1454
	struct tomoyo_policy_namespace *ns =
		container_of(head->r.ns, typeof(*ns), namespace_list);
	struct list_head *list = &ns->policy_list[idx];
	list_for_each_cookie(head->r.acl, list) {
T
Tetsuo Handa 已提交
1455
		struct tomoyo_acl_head *acl =
1456
			container_of(head->r.acl, typeof(*acl), list);
1457 1458
		if (acl->is_deleted)
			continue;
1459 1460
		if (!tomoyo_flush(head))
			return false;
1461
		switch (idx) {
1462
		case TOMOYO_ID_TRANSITION_CONTROL:
1463
			{
1464
				struct tomoyo_transition_control *ptr =
1465
					container_of(acl, typeof(*ptr), head);
1466
				tomoyo_print_namespace(head);
T
Tetsuo Handa 已提交
1467
				tomoyo_set_string(head, tomoyo_transition_type
1468
						  [ptr->type]);
T
Tetsuo Handa 已提交
1469 1470 1471 1472 1473 1474
				tomoyo_set_string(head, ptr->program ?
						  ptr->program->name : "any");
				tomoyo_set_string(head, " from ");
				tomoyo_set_string(head, ptr->domainname ?
						  ptr->domainname->name :
						  "any");
1475 1476 1477 1478
			}
			break;
		case TOMOYO_ID_AGGREGATOR:
			{
T
Tetsuo Handa 已提交
1479
				struct tomoyo_aggregator *ptr =
1480
					container_of(acl, typeof(*ptr), head);
1481
				tomoyo_print_namespace(head);
T
Tetsuo Handa 已提交
1482
				tomoyo_set_string(head, "aggregator ");
1483 1484 1485 1486 1487
				tomoyo_set_string(head,
						  ptr->original_name->name);
				tomoyo_set_space(head);
				tomoyo_set_string(head,
					       ptr->aggregated_name->name);
1488 1489 1490 1491
			}
			break;
		default:
			continue;
1492
		}
1493
		tomoyo_set_lf(head);
1494
	}
1495
	head->r.acl = NULL;
1496 1497 1498 1499
	return true;
}

/**
T
Tetsuo Handa 已提交
1500
 * tomoyo_read_exception - Read exception policy.
1501 1502 1503 1504 1505
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Caller holds tomoyo_read_lock().
 */
T
Tetsuo Handa 已提交
1506
static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
1507
{
1508 1509
	struct tomoyo_policy_namespace *ns =
		container_of(head->r.ns, typeof(*ns), namespace_list);
1510
	if (head->r.eof)
1511
		return;
1512 1513 1514 1515
	while (head->r.step < TOMOYO_MAX_POLICY &&
	       tomoyo_read_policy(head, head->r.step))
		head->r.step++;
	if (head->r.step < TOMOYO_MAX_POLICY)
1516
		return;
1517 1518 1519 1520
	while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
	       tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY))
		head->r.step++;
	if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
1521
		return;
T
Tetsuo Handa 已提交
1522 1523 1524 1525
	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;
1526
		if (!tomoyo_read_domain2(head, &ns->acl_group
T
Tetsuo Handa 已提交
1527 1528 1529 1530
					 [head->r.acl_group_index]))
			return;
		head->r.step++;
	}
1531
	head->r.eof = true;
1532 1533
}

T
Tetsuo Handa 已提交
1534
/* Wait queue for kernel -> userspace notification. */
1535
static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
T
Tetsuo Handa 已提交
1536 1537
/* Wait queue for userspace -> kernel notification. */
static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait);
1538 1539

/* Structure for query. */
T
Tetsuo Handa 已提交
1540
struct tomoyo_query {
1541 1542
	struct list_head list;
	char *query;
T
Tetsuo Handa 已提交
1543
	size_t query_len;
1544
	unsigned int serial;
T
Tetsuo Handa 已提交
1545 1546 1547
	u8 timer;
	u8 answer;
	u8 retry;
1548 1549
};

T
Tetsuo Handa 已提交
1550
/* The list for "struct tomoyo_query". */
1551 1552
static LIST_HEAD(tomoyo_query_list);

T
Tetsuo Handa 已提交
1553 1554 1555
/* Lock for manipulating tomoyo_query_list. */
static DEFINE_SPINLOCK(tomoyo_query_list_lock);

1556 1557 1558 1559 1560 1561
/*
 * Number of "struct file" referring /sys/kernel/security/tomoyo/query
 * interface.
 */
static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);

T
Tetsuo Handa 已提交
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
/**
 * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode.
 *
 * @domain: Pointer to "struct tomoyo_domain_info".
 * @header: Lines containing ACL.
 *
 * Returns nothing.
 */
static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
{
	char *buffer;
	char *cp = strchr(header, '\n');
	int len;
	if (!cp)
		return;
	cp = strchr(cp + 1, '\n');
	if (!cp)
		return;
	*cp++ = '\0';
	len = strlen(cp) + 1;
	buffer = kmalloc(len, GFP_NOFS);
	if (!buffer)
		return;
	snprintf(buffer, len - 1, "%s", cp);
	tomoyo_normalize_line(buffer);
1587 1588 1589
	if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
				  false))
		tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
T
Tetsuo Handa 已提交
1590 1591 1592
	kfree(buffer);
}

1593 1594 1595
/**
 * tomoyo_supervisor - Ask for the supervisor's decision.
 *
T
Tetsuo Handa 已提交
1596 1597
 * @r:   Pointer to "struct tomoyo_request_info".
 * @fmt: The printf()'s format string, followed by parameters.
1598 1599 1600 1601 1602 1603 1604 1605 1606
 *
 * Returns 0 if the supervisor decided to permit the access request which
 * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
 * supervisor decided to retry the access request which violated the policy in
 * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
 */
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
{
	va_list args;
T
Tetsuo Handa 已提交
1607
	int error;
1608 1609
	int len;
	static unsigned int tomoyo_serial;
T
Tetsuo Handa 已提交
1610
	struct tomoyo_query entry = { };
1611
	bool quota_exceeded = false;
T
Tetsuo Handa 已提交
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
	va_start(args, fmt);
	len = vsnprintf((char *) &len, 1, fmt, args) + 1;
	va_end(args);
	/* Write /sys/kernel/security/tomoyo/audit. */
	va_start(args, fmt);
	tomoyo_write_log2(r, len, fmt, args);
	va_end(args);
	/* Nothing more to do if granted. */
	if (r->granted)
		return 0;
1622 1623
	if (r->mode)
		tomoyo_update_stat(r->mode);
1624
	switch (r->mode) {
T
Tetsuo Handa 已提交
1625 1626 1627 1628 1629
	case TOMOYO_CONFIG_ENFORCING:
		error = -EPERM;
		if (atomic_read(&tomoyo_query_observers))
			break;
		goto out;
1630
	case TOMOYO_CONFIG_LEARNING:
T
Tetsuo Handa 已提交
1631 1632 1633 1634
		error = 0;
		/* Check max_learning_entry parameter. */
		if (tomoyo_domain_quota_is_ok(r))
			break;
1635
		/* fall through */
T
Tetsuo Handa 已提交
1636
	default:
1637 1638
		return 0;
	}
T
Tetsuo Handa 已提交
1639
	/* Get message. */
1640
	va_start(args, fmt);
T
Tetsuo Handa 已提交
1641
	entry.query = tomoyo_init_log(r, len, fmt, args);
1642
	va_end(args);
T
Tetsuo Handa 已提交
1643
	if (!entry.query)
1644
		goto out;
T
Tetsuo Handa 已提交
1645 1646 1647
	entry.query_len = strlen(entry.query) + 1;
	if (!error) {
		tomoyo_add_entry(r->domain, entry.query);
1648
		goto out;
T
Tetsuo Handa 已提交
1649 1650
	}
	len = tomoyo_round2(entry.query_len);
1651
	spin_lock(&tomoyo_query_list_lock);
T
Tetsuo Handa 已提交
1652 1653 1654
	if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] &&
	    tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len
	    >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) {
1655 1656
		quota_exceeded = true;
	} else {
T
Tetsuo Handa 已提交
1657 1658 1659 1660
		entry.serial = tomoyo_serial++;
		entry.retry = r->retry;
		tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len;
		list_add_tail(&entry.list, &tomoyo_query_list);
1661 1662 1663 1664 1665
	}
	spin_unlock(&tomoyo_query_list_lock);
	if (quota_exceeded)
		goto out;
	/* Give 10 seconds for supervisor's opinion. */
T
Tetsuo Handa 已提交
1666 1667 1668 1669 1670
	while (entry.timer < 10) {
		wake_up_all(&tomoyo_query_wait);
		if (wait_event_interruptible_timeout
		    (tomoyo_answer_wait, entry.answer ||
		     !atomic_read(&tomoyo_query_observers), HZ))
1671
			break;
T
Tetsuo Handa 已提交
1672 1673
		else
			entry.timer++;
1674 1675
	}
	spin_lock(&tomoyo_query_list_lock);
T
Tetsuo Handa 已提交
1676 1677
	list_del(&entry.list);
	tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len;
1678
	spin_unlock(&tomoyo_query_list_lock);
T
Tetsuo Handa 已提交
1679
	switch (entry.answer) {
1680 1681 1682 1683 1684 1685 1686 1687 1688
	case 3: /* Asked to retry by administrator. */
		error = TOMOYO_RETRY_REQUEST;
		r->retry++;
		break;
	case 1:
		/* Granted by administrator. */
		error = 0;
		break;
	default:
T
Tetsuo Handa 已提交
1689
		/* Timed out or rejected by administrator. */
1690 1691
		break;
	}
T
Tetsuo Handa 已提交
1692 1693
out:
	kfree(entry.query);
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
	return error;
}

/**
 * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
 *
 * @file: Pointer to "struct file".
 * @wait: Pointer to "poll_table".
 *
 * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
 *
 * Waits for access requests which violated policy in enforcing mode.
 */
static int tomoyo_poll_query(struct file *file, poll_table *wait)
{
	struct list_head *tmp;
	bool found = false;
	u8 i;
	for (i = 0; i < 2; i++) {
		spin_lock(&tomoyo_query_list_lock);
		list_for_each(tmp, &tomoyo_query_list) {
T
Tetsuo Handa 已提交
1715 1716
			struct tomoyo_query *ptr =
				list_entry(tmp, typeof(*ptr), list);
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736
			if (ptr->answer)
				continue;
			found = true;
			break;
		}
		spin_unlock(&tomoyo_query_list_lock);
		if (found)
			return POLLIN | POLLRDNORM;
		if (i)
			break;
		poll_wait(file, &tomoyo_query_wait, wait);
	}
	return 0;
}

/**
 * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 */
1737
static void tomoyo_read_query(struct tomoyo_io_buffer *head)
1738 1739
{
	struct list_head *tmp;
T
Tetsuo Handa 已提交
1740 1741
	unsigned int pos = 0;
	size_t len = 0;
1742
	char *buf;
1743
	if (head->r.w_pos)
1744
		return;
1745 1746 1747 1748 1749 1750
	if (head->read_buf) {
		kfree(head->read_buf);
		head->read_buf = NULL;
	}
	spin_lock(&tomoyo_query_list_lock);
	list_for_each(tmp, &tomoyo_query_list) {
T
Tetsuo Handa 已提交
1751
		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
1752 1753
		if (ptr->answer)
			continue;
1754
		if (pos++ != head->r.query_index)
1755 1756 1757 1758 1759 1760
			continue;
		len = ptr->query_len;
		break;
	}
	spin_unlock(&tomoyo_query_list_lock);
	if (!len) {
1761
		head->r.query_index = 0;
1762
		return;
1763
	}
T
Tetsuo Handa 已提交
1764
	buf = kzalloc(len + 32, GFP_NOFS);
1765
	if (!buf)
1766
		return;
1767 1768 1769
	pos = 0;
	spin_lock(&tomoyo_query_list_lock);
	list_for_each(tmp, &tomoyo_query_list) {
T
Tetsuo Handa 已提交
1770
		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
1771 1772
		if (ptr->answer)
			continue;
1773
		if (pos++ != head->r.query_index)
1774 1775 1776 1777 1778 1779
			continue;
		/*
		 * Some query can be skipped because tomoyo_query_list
		 * can change, but I don't care.
		 */
		if (len == ptr->query_len)
T
Tetsuo Handa 已提交
1780 1781
			snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
				 ptr->retry, ptr->query);
1782 1783 1784 1785 1786
		break;
	}
	spin_unlock(&tomoyo_query_list_lock);
	if (buf[0]) {
		head->read_buf = buf;
1787 1788
		head->r.w[head->r.w_pos++] = buf;
		head->r.query_index++;
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
	} else {
		kfree(buf);
	}
}

/**
 * tomoyo_write_answer - Write the supervisor's decision.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0 on success, -EINVAL otherwise.
 */
static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
{
	char *data = head->write_buf;
	struct list_head *tmp;
	unsigned int serial;
	unsigned int answer;
	spin_lock(&tomoyo_query_list_lock);
	list_for_each(tmp, &tomoyo_query_list) {
T
Tetsuo Handa 已提交
1809
		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
1810 1811 1812 1813 1814 1815 1816
		ptr->timer = 0;
	}
	spin_unlock(&tomoyo_query_list_lock);
	if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
		return -EINVAL;
	spin_lock(&tomoyo_query_list_lock);
	list_for_each(tmp, &tomoyo_query_list) {
T
Tetsuo Handa 已提交
1817
		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
		if (ptr->serial != serial)
			continue;
		if (!ptr->answer)
			ptr->answer = answer;
		break;
	}
	spin_unlock(&tomoyo_query_list_lock);
	return 0;
}

1828 1829 1830 1831 1832 1833 1834
/**
 * tomoyo_read_version: Get version.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns version information.
 */
1835
static void tomoyo_read_version(struct tomoyo_io_buffer *head)
1836
{
1837
	if (!head->r.eof) {
1838
		tomoyo_io_printf(head, "2.4.0");
1839
		head->r.eof = true;
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849
	}
}

/**
 * tomoyo_read_self_domain - Get the current process's domainname.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns the current process's domainname.
 */
1850
static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
1851
{
1852
	if (!head->r.eof) {
1853 1854 1855 1856 1857 1858
		/*
		 * tomoyo_domain()->domainname != NULL
		 * because every process belongs to a domain and
		 * the domain's name cannot be NULL.
		 */
		tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
1859
		head->r.eof = true;
1860 1861 1862
	}
}

1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
/* String table for /sys/kernel/security/tomoyo/stat interface. */
static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = {
	[TOMOYO_STAT_POLICY_UPDATES]    = "update:",
	[TOMOYO_STAT_POLICY_LEARNING]   = "violation in learning mode:",
	[TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
	[TOMOYO_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
};

/* String table for /sys/kernel/security/tomoyo/stat interface. */
static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
	[TOMOYO_MEMORY_POLICY] = "policy:",
	[TOMOYO_MEMORY_AUDIT]  = "audit log:",
	[TOMOYO_MEMORY_QUERY]  = "query message:",
};

/* Timestamp counter for last updated. */
static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
/* Counter for number of updates. */
static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];

/**
 * tomoyo_update_stat - Update statistic counters.
 *
 * @index: Index for policy type.
 *
 * Returns nothing.
 */
void tomoyo_update_stat(const u8 index)
{
	struct timeval tv;
	do_gettimeofday(&tv);
	/*
	 * I don't use atomic operations because race condition is not fatal.
	 */
	tomoyo_stat_updated[index]++;
	tomoyo_stat_modified[index] = tv.tv_sec;
}

/**
 * tomoyo_read_stat - Read statistic data.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns nothing.
 */
static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
{
	u8 i;
	unsigned int total = 0;
	if (head->r.eof)
		return;
	for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) {
		tomoyo_io_printf(head, "Policy %-30s %10u",
				 tomoyo_policy_headers[i],
				 tomoyo_stat_updated[i]);
		if (tomoyo_stat_modified[i]) {
			struct tomoyo_time stamp;
			tomoyo_convert_time(tomoyo_stat_modified[i], &stamp);
			tomoyo_io_printf(head, " (Last: %04u/%02u/%02u "
					 "%02u:%02u:%02u)",
					 stamp.year, stamp.month, stamp.day,
					 stamp.hour, stamp.min, stamp.sec);
		}
		tomoyo_set_lf(head);
	}
	for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) {
		unsigned int used = tomoyo_memory_used[i];
		total += used;
		tomoyo_io_printf(head, "Memory used by %-22s %10u",
				 tomoyo_memory_headers[i], used);
		used = tomoyo_memory_quota[i];
		if (used)
			tomoyo_io_printf(head, " (Quota: %10u)", used);
		tomoyo_set_lf(head);
	}
	tomoyo_io_printf(head, "Total memory used:                    %10u\n",
			 total);
	head->r.eof = true;
}

/**
 * tomoyo_write_stat - Set memory quota.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns 0.
 */
static int tomoyo_write_stat(struct tomoyo_io_buffer *head)
{
	char *data = head->write_buf;
	u8 i;
	if (tomoyo_str_starts(&data, "Memory used by "))
		for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++)
			if (tomoyo_str_starts(&data, tomoyo_memory_headers[i]))
				sscanf(data, "%u", &tomoyo_memory_quota[i]);
	return 0;
}

1961 1962 1963 1964 1965 1966
/**
 * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
 *
 * @type: Type of interface.
 * @file: Pointer to "struct file".
 *
T
Tetsuo Handa 已提交
1967
 * Returns 0 on success, negative value otherwise.
1968
 */
1969
int tomoyo_open_control(const u8 type, struct file *file)
1970
{
1971
	struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
1972 1973 1974 1975

	if (!head)
		return -ENOMEM;
	mutex_init(&head->io_sem);
1976
	head->type = type;
1977 1978 1979
	switch (type) {
	case TOMOYO_DOMAINPOLICY:
		/* /sys/kernel/security/tomoyo/domain_policy */
T
Tetsuo Handa 已提交
1980 1981
		head->write = tomoyo_write_domain;
		head->read = tomoyo_read_domain;
1982 1983 1984
		break;
	case TOMOYO_EXCEPTIONPOLICY:
		/* /sys/kernel/security/tomoyo/exception_policy */
T
Tetsuo Handa 已提交
1985 1986
		head->write = tomoyo_write_exception;
		head->read = tomoyo_read_exception;
1987
		break;
T
Tetsuo Handa 已提交
1988 1989 1990 1991 1992
	case TOMOYO_AUDIT:
		/* /sys/kernel/security/tomoyo/audit */
		head->poll = tomoyo_poll_log;
		head->read = tomoyo_read_log;
		break;
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011
	case TOMOYO_SELFDOMAIN:
		/* /sys/kernel/security/tomoyo/self_domain */
		head->read = tomoyo_read_self_domain;
		break;
	case TOMOYO_DOMAIN_STATUS:
		/* /sys/kernel/security/tomoyo/.domain_status */
		head->write = tomoyo_write_domain_profile;
		head->read = tomoyo_read_domain_profile;
		break;
	case TOMOYO_PROCESS_STATUS:
		/* /sys/kernel/security/tomoyo/.process_status */
		head->write = tomoyo_write_pid;
		head->read = tomoyo_read_pid;
		break;
	case TOMOYO_VERSION:
		/* /sys/kernel/security/tomoyo/version */
		head->read = tomoyo_read_version;
		head->readbuf_size = 128;
		break;
2012 2013 2014 2015 2016
	case TOMOYO_STAT:
		/* /sys/kernel/security/tomoyo/stat */
		head->write = tomoyo_write_stat;
		head->read = tomoyo_read_stat;
		head->readbuf_size = 1024;
2017 2018 2019 2020 2021 2022
		break;
	case TOMOYO_PROFILE:
		/* /sys/kernel/security/tomoyo/profile */
		head->write = tomoyo_write_profile;
		head->read = tomoyo_read_profile;
		break;
2023 2024 2025 2026 2027
	case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
		head->poll = tomoyo_poll_query;
		head->write = tomoyo_write_answer;
		head->read = tomoyo_read_query;
		break;
2028 2029
	case TOMOYO_MANAGER:
		/* /sys/kernel/security/tomoyo/manager */
T
Tetsuo Handa 已提交
2030 2031
		head->write = tomoyo_write_manager;
		head->read = tomoyo_read_manager;
2032 2033 2034 2035 2036 2037 2038 2039
		break;
	}
	if (!(file->f_mode & FMODE_READ)) {
		/*
		 * No need to allocate read_buf since it is not opened
		 * for reading.
		 */
		head->read = NULL;
2040 2041 2042
		head->poll = NULL;
	} else if (!head->poll) {
		/* Don't allocate read_buf for poll() access. */
2043 2044
		if (!head->readbuf_size)
			head->readbuf_size = 4096 * 2;
2045
		head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
2046
		if (!head->read_buf) {
2047
			kfree(head);
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058
			return -ENOMEM;
		}
	}
	if (!(file->f_mode & FMODE_WRITE)) {
		/*
		 * No need to allocate write_buf since it is not opened
		 * for writing.
		 */
		head->write = NULL;
	} else if (head->write) {
		head->writebuf_size = 4096 * 2;
2059
		head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS);
2060
		if (!head->write_buf) {
2061 2062
			kfree(head->read_buf);
			kfree(head);
2063 2064 2065
			return -ENOMEM;
		}
	}
2066 2067 2068 2069 2070 2071
	/*
	 * If the file is /sys/kernel/security/tomoyo/query , increment the
	 * observer counter.
	 * The obserber counter is used by tomoyo_supervisor() to see if
	 * there is some process monitoring /sys/kernel/security/tomoyo/query.
	 */
T
Tetsuo Handa 已提交
2072
	if (type == TOMOYO_QUERY)
2073
		atomic_inc(&tomoyo_query_observers);
T
Tetsuo Handa 已提交
2074 2075
	file->private_data = head;
	tomoyo_notify_gc(head, true);
2076 2077 2078
	return 0;
}

T
Tetsuo Handa 已提交
2079 2080 2081 2082 2083 2084 2085
/**
 * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
 *
 * @file: Pointer to "struct file".
 * @wait: Pointer to "poll_table".
 *
 * Waits for read readiness.
T
Tetsuo Handa 已提交
2086 2087
 * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and
 * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd.
T
Tetsuo Handa 已提交
2088 2089 2090 2091 2092 2093 2094 2095 2096
 */
int tomoyo_poll_control(struct file *file, poll_table *wait)
{
	struct tomoyo_io_buffer *head = file->private_data;
	if (!head->poll)
		return -ENOSYS;
	return head->poll(file, wait);
}

2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135
/**
 * tomoyo_set_namespace_cursor - Set namespace to read.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns nothing.
 */
static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
{
	struct list_head *ns;
	if (head->type != TOMOYO_EXCEPTIONPOLICY &&
	    head->type != TOMOYO_PROFILE)
		return;
	/*
	 * If this is the first read, or reading previous namespace finished
	 * and has more namespaces to read, update the namespace cursor.
	 */
	ns = head->r.ns;
	if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) {
		/* Clearing is OK because tomoyo_flush() returned true. */
		memset(&head->r, 0, sizeof(head->r));
		head->r.ns = ns ? ns->next : tomoyo_namespace_list.next;
	}
}

/**
 * tomoyo_has_more_namespace - Check for unread namespaces.
 *
 * @head: Pointer to "struct tomoyo_io_buffer".
 *
 * Returns true if we have more entries to print, false otherwise.
 */
static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head)
{
	return (head->type == TOMOYO_EXCEPTIONPOLICY ||
		head->type == TOMOYO_PROFILE) && head->r.eof &&
		head->r.ns->next != &tomoyo_namespace_list;
}

2136 2137 2138
/**
 * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
 *
T
Tetsuo Handa 已提交
2139
 * @head:       Pointer to "struct tomoyo_io_buffer".
2140 2141 2142 2143 2144
 * @buffer:     Poiner to buffer to write to.
 * @buffer_len: Size of @buffer.
 *
 * Returns bytes read on success, negative value otherwise.
 */
T
Tetsuo Handa 已提交
2145 2146
ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
			    const int buffer_len)
2147
{
2148
	int len;
T
Tetsuo Handa 已提交
2149
	int idx;
2150 2151 2152 2153 2154

	if (!head->read)
		return -ENOSYS;
	if (mutex_lock_interruptible(&head->io_sem))
		return -EINTR;
2155 2156
	head->read_user_buf = buffer;
	head->read_user_buf_avail = buffer_len;
T
Tetsuo Handa 已提交
2157
	idx = tomoyo_read_lock();
2158 2159
	if (tomoyo_flush(head))
		/* Call the policy handler. */
2160 2161 2162 2163 2164
		do {
			tomoyo_set_namespace_cursor(head);
			head->read(head);
		} while (tomoyo_flush(head) &&
			 tomoyo_has_more_namespace(head));
T
Tetsuo Handa 已提交
2165
	tomoyo_read_unlock(idx);
2166
	len = head->read_user_buf - buffer;
2167 2168 2169 2170
	mutex_unlock(&head->io_sem);
	return len;
}

2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
/**
 * tomoyo_parse_policy - Parse a policy line.
 *
 * @head: Poiter to "struct tomoyo_io_buffer".
 * @line: Line to parse.
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
{
	/* Delete request? */
	head->w.is_delete = !strncmp(line, "delete ", 7);
	if (head->w.is_delete)
		memmove(line, line + 7, strlen(line + 7) + 1);
	/* Selecting namespace to update. */
	if (head->type == TOMOYO_EXCEPTIONPOLICY ||
	    head->type == TOMOYO_PROFILE) {
		if (*line == '<') {
			char *cp = strchr(line, ' ');
			if (cp) {
				*cp++ = '\0';
				head->w.ns = tomoyo_assign_namespace(line);
				memmove(line, cp, strlen(cp) + 1);
			} else
				head->w.ns = NULL;
		} else
			head->w.ns = &tomoyo_kernel_namespace;
		/* Don't allow updating if namespace is invalid. */
		if (!head->w.ns)
			return -ENOENT;
	}
	/* Do the update. */
	return head->write(head);
}

2208 2209 2210
/**
 * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
 *
T
Tetsuo Handa 已提交
2211
 * @head:       Pointer to "struct tomoyo_io_buffer".
2212 2213 2214 2215 2216
 * @buffer:     Pointer to buffer to read from.
 * @buffer_len: Size of @buffer.
 *
 * Returns @buffer_len on success, negative value otherwise.
 */
T
Tetsuo Handa 已提交
2217 2218
ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
			     const char __user *buffer, const int buffer_len)
2219 2220
{
	int error = buffer_len;
2221
	size_t avail_len = buffer_len;
2222
	char *cp0 = head->write_buf;
T
Tetsuo Handa 已提交
2223
	int idx;
2224 2225 2226 2227 2228 2229
	if (!head->write)
		return -ENOSYS;
	if (!access_ok(VERIFY_READ, buffer, buffer_len))
		return -EFAULT;
	if (mutex_lock_interruptible(&head->io_sem))
		return -EINTR;
T
Tetsuo Handa 已提交
2230
	idx = tomoyo_read_lock();
2231 2232 2233
	/* Read a line and dispatch it to the policy handler. */
	while (avail_len > 0) {
		char c;
T
Tetsuo Handa 已提交
2234
		if (head->w.avail >= head->writebuf_size - 1) {
2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
			const int len = head->writebuf_size * 2;
			char *cp = kzalloc(len, GFP_NOFS);
			if (!cp) {
				error = -ENOMEM;
				break;
			}
			memmove(cp, cp0, head->w.avail);
			kfree(cp0);
			head->write_buf = cp;
			cp0 = cp;
			head->writebuf_size = len;
		}
		if (get_user(c, buffer)) {
2248 2249 2250 2251 2252
			error = -EFAULT;
			break;
		}
		buffer++;
		avail_len--;
T
Tetsuo Handa 已提交
2253
		cp0[head->w.avail++] = c;
2254 2255
		if (c != '\n')
			continue;
T
Tetsuo Handa 已提交
2256 2257
		cp0[head->w.avail - 1] = '\0';
		head->w.avail = 0;
2258
		tomoyo_normalize_line(cp0);
2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289
		if (!strcmp(cp0, "reset")) {
			head->w.ns = &tomoyo_kernel_namespace;
			head->w.domain = NULL;
			memset(&head->r, 0, sizeof(head->r));
			continue;
		}
		/* Don't allow updating policies by non manager programs. */
		switch (head->type) {
		case TOMOYO_PROCESS_STATUS:
			/* This does not write anything. */
			break;
		case TOMOYO_DOMAINPOLICY:
			if (tomoyo_select_domain(head, cp0))
				continue;
			/* fall through */
		case TOMOYO_EXCEPTIONPOLICY:
			if (!strcmp(cp0, "select transition_only")) {
				head->r.print_transition_related_only = true;
				continue;
			}
			/* fall through */
		default:
			if (!tomoyo_manager()) {
				error = -EPERM;
				goto out;
			}
		}
		switch (tomoyo_parse_policy(head, cp0)) {
		case -EPERM:
			error = -EPERM;
			goto out;
2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303
		case 0:
			switch (head->type) {
			case TOMOYO_DOMAINPOLICY:
			case TOMOYO_EXCEPTIONPOLICY:
			case TOMOYO_DOMAIN_STATUS:
			case TOMOYO_STAT:
			case TOMOYO_PROFILE:
			case TOMOYO_MANAGER:
				tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
				break;
			default:
				break;
			}
			break;
2304
		}
2305
	}
2306
out:
T
Tetsuo Handa 已提交
2307
	tomoyo_read_unlock(idx);
2308 2309 2310 2311 2312 2313 2314
	mutex_unlock(&head->io_sem);
	return error;
}

/**
 * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
 *
T
Tetsuo Handa 已提交
2315
 * @head: Pointer to "struct tomoyo_io_buffer".
2316
 *
T
Tetsuo Handa 已提交
2317
 * Returns 0.
2318
 */
T
Tetsuo Handa 已提交
2319
int tomoyo_close_control(struct tomoyo_io_buffer *head)
2320
{
2321 2322 2323 2324
	/*
	 * If the file is /sys/kernel/security/tomoyo/query , decrement the
	 * observer counter.
	 */
T
Tetsuo Handa 已提交
2325 2326 2327 2328
	if (head->type == TOMOYO_QUERY &&
	    atomic_dec_and_test(&tomoyo_query_observers))
		wake_up_all(&tomoyo_answer_wait);
	tomoyo_notify_gc(head, false);
2329 2330 2331 2332
	return 0;
}

/**
2333
 * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
2334
 */
2335
void tomoyo_check_profile(void)
2336
{
2337 2338 2339
	struct tomoyo_domain_info *domain;
	const int idx = tomoyo_read_lock();
	tomoyo_policy_loaded = true;
2340
	printk(KERN_INFO "TOMOYO: 2.4.0\n");
2341 2342
	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
		const u8 profile = domain->profile;
2343 2344 2345 2346 2347 2348 2349 2350 2351 2352
		const struct tomoyo_policy_namespace *ns = domain->ns;
		if (ns->profile_version != 20100903)
			printk(KERN_ERR
			       "Profile version %u is not supported.\n",
			       ns->profile_version);
		else if (!ns->profile_ptr[profile])
			printk(KERN_ERR
			       "Profile %u (used by '%s') is not defined.\n",
			       profile, domain->domainname->name);
		else
2353
			continue;
2354 2355 2356 2357
		printk(KERN_ERR
		       "Userland tools for TOMOYO 2.4 must be installed and "
		       "policy must be initialized.\n");
		printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ "
2358
		       "for more information.\n");
2359
		panic("STOP!");
2360 2361 2362
	}
	tomoyo_read_unlock(idx);
	printk(KERN_INFO "Mandatory Access Control activated.\n");
2363
}
2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423

/**
 * tomoyo_load_builtin_policy - Load built-in policy.
 *
 * Returns nothing.
 */
void __init tomoyo_load_builtin_policy(void)
{
	/*
	 * This include file is manually created and contains built-in policy
	 * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy",
	 * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager",
	 * "tomoyo_builtin_stat" in the form of "static char [] __initdata".
	 */
#include "builtin-policy.h"
	u8 i;
	const int idx = tomoyo_read_lock();
	for (i = 0; i < 5; i++) {
		struct tomoyo_io_buffer head = { };
		char *start = "";
		switch (i) {
		case 0:
			start = tomoyo_builtin_profile;
			head.type = TOMOYO_PROFILE;
			head.write = tomoyo_write_profile;
			break;
		case 1:
			start = tomoyo_builtin_exception_policy;
			head.type = TOMOYO_EXCEPTIONPOLICY;
			head.write = tomoyo_write_exception;
			break;
		case 2:
			start = tomoyo_builtin_domain_policy;
			head.type = TOMOYO_DOMAINPOLICY;
			head.write = tomoyo_write_domain;
			break;
		case 3:
			start = tomoyo_builtin_manager;
			head.type = TOMOYO_MANAGER;
			head.write = tomoyo_write_manager;
			break;
		case 4:
			start = tomoyo_builtin_stat;
			head.type = TOMOYO_STAT;
			head.write = tomoyo_write_stat;
			break;
		}
		while (1) {
			char *end = strchr(start, '\n');
			if (!end)
				break;
			*end = '\0';
			tomoyo_normalize_line(start);
			head.write_buf = start;
			tomoyo_parse_policy(&head, start);
			start = end + 1;
		}
	}
	tomoyo_read_unlock(idx);
}