[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/Kconfig b/ap/os/linux/linux-3.4.x/security/tomoyo/Kconfig
new file mode 100644
index 0000000..8eb779b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/Kconfig
@@ -0,0 +1,74 @@
+config SECURITY_TOMOYO
+	bool "TOMOYO Linux Support"
+	depends on SECURITY
+	depends on NET
+	select SECURITYFS
+	select SECURITY_PATH
+	select SECURITY_NETWORK
+	default n
+	help
+	  This selects TOMOYO Linux, pathname-based access control.
+	  Required userspace tools and further information may be
+	  found at <http://tomoyo.sourceforge.jp/>.
+	  If you are unsure how to answer this question, answer N.
+
+config SECURITY_TOMOYO_MAX_ACCEPT_ENTRY
+	int "Default maximal count for learning mode"
+	default 2048
+	range 0 2147483647
+	depends on SECURITY_TOMOYO
+	help
+	  This is the default value for maximal ACL entries
+	  that are automatically appended into policy at "learning mode".
+	  Some programs access thousands of objects, so running
+	  such programs in "learning mode" dulls the system response
+	  and consumes much memory.
+	  This is the safeguard for such programs.
+
+config SECURITY_TOMOYO_MAX_AUDIT_LOG
+	int "Default maximal count for audit log"
+	default 1024
+	range 0 2147483647
+	depends on SECURITY_TOMOYO
+	help
+	  This is the default value for maximal entries for
+	  audit logs that the kernel can hold on memory.
+	  You can read the log via /sys/kernel/security/tomoyo/audit.
+	  If you don't need audit logs, you may set this value to 0.
+
+config SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+	bool "Activate without calling userspace policy loader."
+	default n
+	depends on SECURITY_TOMOYO
+	---help---
+	  Say Y here if you want to activate access control as soon as built-in
+	  policy was loaded. This option will be useful for systems where
+	  operations which can lead to the hijacking of the boot sequence are
+	  needed before loading the policy. For example, you can activate
+	  immediately after loading the fixed part of policy which will allow
+	  only operations needed for mounting a partition which contains the
+	  variant part of policy and verifying (e.g. running GPG check) and
+	  loading the variant part of policy. Since you can start using
+	  enforcing mode from the beginning, you can reduce the possibility of
+	  hijacking the boot sequence.
+
+config SECURITY_TOMOYO_POLICY_LOADER
+	string "Location of userspace policy loader"
+	default "/sbin/tomoyo-init"
+	depends on SECURITY_TOMOYO
+	depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+	---help---
+	  This is the default pathname of policy loader which is called before
+	  activation. You can override this setting via TOMOYO_loader= kernel
+	  command line option.
+
+config SECURITY_TOMOYO_ACTIVATION_TRIGGER
+	string "Trigger for calling userspace policy loader"
+	default "/sbin/init"
+	depends on SECURITY_TOMOYO
+	depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+	---help---
+	  This is the default pathname of activation trigger.
+	  You can override this setting via TOMOYO_trigger= kernel command line
+	  option. For example, if you pass init=/bin/systemd option, you may
+	  want to also pass TOMOYO_trigger=/bin/systemd option.
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/Makefile b/ap/os/linux/linux-3.4.x/security/tomoyo/Makefile
new file mode 100644
index 0000000..56a0c7b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/Makefile
@@ -0,0 +1,48 @@
+obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o
+
+$(obj)/policy/profile.conf:
+	@mkdir -p $(obj)/policy/
+	@echo Creating an empty policy/profile.conf
+	@touch $@
+
+$(obj)/policy/exception_policy.conf:
+	@mkdir -p $(obj)/policy/
+	@echo Creating a default policy/exception_policy.conf
+	@echo initialize_domain /sbin/modprobe from any >> $@
+	@echo initialize_domain /sbin/hotplug from any >> $@
+
+$(obj)/policy/domain_policy.conf:
+	@mkdir -p $(obj)/policy/
+	@echo Creating an empty policy/domain_policy.conf
+	@touch $@
+
+$(obj)/policy/manager.conf:
+	@mkdir -p $(obj)/policy/
+	@echo Creating an empty policy/manager.conf
+	@touch $@
+
+$(obj)/policy/stat.conf:
+	@mkdir -p $(obj)/policy/
+	@echo Creating an empty policy/stat.conf
+	@touch $@
+
+$(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf
+	@echo Generating built-in policy for TOMOYO 2.5.x.
+	@echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp
+	@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp
+	@echo "\"\";" >> $@.tmp
+	@echo "static char tomoyo_builtin_exception_policy[] __initdata =" >> $@.tmp
+	@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/exception_policy.conf >> $@.tmp
+	@echo "\"\";" >> $@.tmp
+	@echo "static char tomoyo_builtin_domain_policy[] __initdata =" >> $@.tmp
+	@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/domain_policy.conf >> $@.tmp
+	@echo "\"\";" >> $@.tmp
+	@echo "static char tomoyo_builtin_manager[] __initdata =" >> $@.tmp
+	@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/manager.conf >> $@.tmp
+	@echo "\"\";" >> $@.tmp
+	@echo "static char tomoyo_builtin_stat[] __initdata =" >> $@.tmp
+	@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/stat.conf >> $@.tmp
+	@echo "\"\";" >> $@.tmp
+	@mv $@.tmp $@
+
+$(obj)/common.o: $(obj)/builtin-policy.h
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/audit.c b/ap/os/linux/linux-3.4.x/security/tomoyo/audit.c
new file mode 100644
index 0000000..7ef9fa3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/audit.c
@@ -0,0 +1,461 @@
+/*
+ * security/tomoyo/audit.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/**
+ * tomoyo_print_bprm - Print "struct linux_binprm" for auditing.
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ * @dump: Pointer to "struct tomoyo_page_dump".
+ *
+ * Returns the contents of @bprm on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_print_bprm(struct linux_binprm *bprm,
+			       struct tomoyo_page_dump *dump)
+{
+	static const int tomoyo_buffer_len = 4096 * 2;
+	char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS);
+	char *cp;
+	char *last_start;
+	int len;
+	unsigned long pos = bprm->p;
+	int offset = pos % PAGE_SIZE;
+	int argv_count = bprm->argc;
+	int envp_count = bprm->envc;
+	bool truncated = false;
+	if (!buffer)
+		return NULL;
+	len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
+	cp = buffer + len;
+	if (!argv_count) {
+		memmove(cp, "} envp[]={ ", 11);
+		cp += 11;
+	}
+	last_start = cp;
+	while (argv_count || envp_count) {
+		if (!tomoyo_dump_page(bprm, pos, dump))
+			goto out;
+		pos += PAGE_SIZE - offset;
+		/* Read. */
+		while (offset < PAGE_SIZE) {
+			const char *kaddr = dump->data;
+			const unsigned char c = kaddr[offset++];
+			if (cp == last_start)
+				*cp++ = '"';
+			if (cp >= buffer + tomoyo_buffer_len - 32) {
+				/* Reserve some room for "..." string. */
+				truncated = true;
+			} else if (c == '\\') {
+				*cp++ = '\\';
+				*cp++ = '\\';
+			} else if (c > ' ' && c < 127) {
+				*cp++ = c;
+			} else if (!c) {
+				*cp++ = '"';
+				*cp++ = ' ';
+				last_start = cp;
+			} else {
+				*cp++ = '\\';
+				*cp++ = (c >> 6) + '0';
+				*cp++ = ((c >> 3) & 7) + '0';
+				*cp++ = (c & 7) + '0';
+			}
+			if (c)
+				continue;
+			if (argv_count) {
+				if (--argv_count == 0) {
+					if (truncated) {
+						cp = last_start;
+						memmove(cp, "... ", 4);
+						cp += 4;
+					}
+					memmove(cp, "} envp[]={ ", 11);
+					cp += 11;
+					last_start = cp;
+					truncated = false;
+				}
+			} else if (envp_count) {
+				if (--envp_count == 0) {
+					if (truncated) {
+						cp = last_start;
+						memmove(cp, "... ", 4);
+						cp += 4;
+					}
+				}
+			}
+			if (!argv_count && !envp_count)
+				break;
+		}
+		offset = 0;
+	}
+	*cp++ = '}';
+	*cp = '\0';
+	return buffer;
+out:
+	snprintf(buffer, tomoyo_buffer_len - 1,
+		 "argv[]={ ... } envp[]= { ... }");
+	return buffer;
+}
+
+/**
+ * tomoyo_filetype - Get string representation of file type.
+ *
+ * @mode: Mode value for stat().
+ *
+ * Returns file type string.
+ */
+static inline const char *tomoyo_filetype(const umode_t mode)
+{
+	switch (mode & S_IFMT) {
+	case S_IFREG:
+	case 0:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE];
+	case S_IFDIR:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY];
+	case S_IFLNK:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK];
+	case S_IFIFO:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO];
+	case S_IFSOCK:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET];
+	case S_IFBLK:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV];
+	case S_IFCHR:
+		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV];
+	}
+	return "unknown"; /* This should not happen. */
+}
+
+/**
+ * tomoyo_print_header - Get header line of audit log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns string representation.
+ *
+ * This function uses kmalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_print_header(struct tomoyo_request_info *r)
+{
+	struct tomoyo_time stamp;
+	const pid_t gpid = task_pid_nr(current);
+	struct tomoyo_obj_info *obj = r->obj;
+	static const int tomoyo_buffer_len = 4096;
+	char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+	int pos;
+	u8 i;
+	if (!buffer)
+		return NULL;
+	{
+		struct timeval tv;
+		do_gettimeofday(&tv);
+		tomoyo_convert_time(tv.tv_sec, &stamp);
+	}
+	pos = snprintf(buffer, tomoyo_buffer_len - 1,
+		       "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
+		       "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
+		       "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
+		       "fsuid=%u fsgid=%u }", stamp.year, stamp.month,
+		       stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile,
+		       tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid,
+		       tomoyo_sys_getpid(), tomoyo_sys_getppid(),
+		       current_uid(), current_gid(), current_euid(),
+		       current_egid(), current_suid(), current_sgid(),
+		       current_fsuid(), current_fsgid());
+	if (!obj)
+		goto no_obj_info;
+	if (!obj->validate_done) {
+		tomoyo_get_attributes(obj);
+		obj->validate_done = true;
+	}
+	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
+		struct tomoyo_mini_stat *stat;
+		unsigned int dev;
+		umode_t mode;
+		if (!obj->stat_valid[i])
+			continue;
+		stat = &obj->stat[i];
+		dev = stat->dev;
+		mode = stat->mode;
+		if (i & 1) {
+			pos += snprintf(buffer + pos,
+					tomoyo_buffer_len - 1 - pos,
+					" path%u.parent={ uid=%u gid=%u "
+					"ino=%lu perm=0%o }", (i >> 1) + 1,
+					stat->uid, stat->gid, (unsigned long)
+					stat->ino, stat->mode & S_IALLUGO);
+			continue;
+		}
+		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
+				" path%u={ uid=%u gid=%u ino=%lu major=%u"
+				" minor=%u perm=0%o type=%s", (i >> 1) + 1,
+				stat->uid, stat->gid, (unsigned long)
+				stat->ino, MAJOR(dev), MINOR(dev),
+				mode & S_IALLUGO, tomoyo_filetype(mode));
+		if (S_ISCHR(mode) || S_ISBLK(mode)) {
+			dev = stat->rdev;
+			pos += snprintf(buffer + pos,
+					tomoyo_buffer_len - 1 - pos,
+					" dev_major=%u dev_minor=%u",
+					MAJOR(dev), MINOR(dev));
+		}
+		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
+				" }");
+	}
+no_obj_info:
+	if (pos < tomoyo_buffer_len - 1)
+		return buffer;
+	kfree(buffer);
+	return NULL;
+}
+
+/**
+ * tomoyo_init_log - Allocate buffer for audit logs.
+ *
+ * @r:    Pointer to "struct tomoyo_request_info".
+ * @len:  Buffer size needed for @fmt and @args.
+ * @fmt:  The printf()'s format string.
+ * @args: va_list structure for @fmt.
+ *
+ * Returns pointer to allocated memory.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
+		      va_list args)
+{
+	char *buf = NULL;
+	char *bprm_info = NULL;
+	const char *header = NULL;
+	char *realpath = NULL;
+	const char *symlink = NULL;
+	int pos;
+	const char *domainname = r->domain->domainname->name;
+	header = tomoyo_print_header(r);
+	if (!header)
+		return NULL;
+	/* +10 is for '\n' etc. and '\0'. */
+	len += strlen(domainname) + strlen(header) + 10;
+	if (r->ee) {
+		struct file *file = r->ee->bprm->file;
+		realpath = tomoyo_realpath_from_path(&file->f_path);
+		bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
+		if (!realpath || !bprm_info)
+			goto out;
+		/* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
+		len += strlen(realpath) + 80 + strlen(bprm_info);
+	} else if (r->obj && r->obj->symlink_target) {
+		symlink = r->obj->symlink_target->name;
+		/* +18 is for " symlink.target=\"%s\"" */
+		len += 18 + strlen(symlink);
+	}
+	len = tomoyo_round2(len);
+	buf = kzalloc(len, GFP_NOFS);
+	if (!buf)
+		goto out;
+	len--;
+	pos = snprintf(buf, len, "%s", header);
+	if (realpath) {
+		struct linux_binprm *bprm = r->ee->bprm;
+		pos += snprintf(buf + pos, len - pos,
+				" exec={ realpath=\"%s\" argc=%d envc=%d %s }",
+				realpath, bprm->argc, bprm->envc, bprm_info);
+	} else if (symlink)
+		pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
+				symlink);
+	pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
+	vsnprintf(buf + pos, len - pos, fmt, args);
+out:
+	kfree(realpath);
+	kfree(bprm_info);
+	kfree(header);
+	return buf;
+}
+
+/* Wait queue for /sys/kernel/security/tomoyo/audit. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait);
+
+/* Structure for audit log. */
+struct tomoyo_log {
+	struct list_head list;
+	char *log;
+	int size;
+};
+
+/* The list for "struct tomoyo_log". */
+static LIST_HEAD(tomoyo_log);
+
+/* Lock for "struct list_head tomoyo_log". */
+static DEFINE_SPINLOCK(tomoyo_log_lock);
+
+/* Length of "stuct list_head tomoyo_log". */
+static unsigned int tomoyo_log_count;
+
+/**
+ * tomoyo_get_audit - Get audit mode.
+ *
+ * @ns:          Pointer to "struct tomoyo_policy_namespace".
+ * @profile:     Profile number.
+ * @index:       Index number of functionality.
+ * @is_granted:  True if granted log, false otherwise.
+ *
+ * Returns true if this request should be audited, false otherwise.
+ */
+static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
+			     const u8 profile, const u8 index,
+			     const struct tomoyo_acl_info *matched_acl,
+			     const bool is_granted)
+{
+	u8 mode;
+	const u8 category = tomoyo_index2category[index] +
+		TOMOYO_MAX_MAC_INDEX;
+	struct tomoyo_profile *p;
+	if (!tomoyo_policy_loaded)
+		return false;
+	p = tomoyo_profile(ns, profile);
+	if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
+		return false;
+	if (is_granted && matched_acl && matched_acl->cond &&
+	    matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
+		return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
+	mode = p->config[index];
+	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+		mode = p->config[category];
+	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+		mode = p->default_config;
+	if (is_granted)
+		return mode & TOMOYO_CONFIG_WANT_GRANT_LOG;
+	return mode & TOMOYO_CONFIG_WANT_REJECT_LOG;
+}
+
+/**
+ * tomoyo_write_log2 - Write an audit log.
+ *
+ * @r:    Pointer to "struct tomoyo_request_info".
+ * @len:  Buffer size needed for @fmt and @args.
+ * @fmt:  The printf()'s format string.
+ * @args: va_list structure for @fmt.
+ *
+ * Returns nothing.
+ */
+void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
+		       va_list args)
+{
+	char *buf;
+	struct tomoyo_log *entry;
+	bool quota_exceeded = false;
+	if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
+			      r->matched_acl, r->granted))
+		goto out;
+	buf = tomoyo_init_log(r, len, fmt, args);
+	if (!buf)
+		goto out;
+	entry = kzalloc(sizeof(*entry), GFP_NOFS);
+	if (!entry) {
+		kfree(buf);
+		goto out;
+	}
+	entry->log = buf;
+	len = tomoyo_round2(strlen(buf) + 1);
+	/*
+	 * The entry->size is used for memory quota checks.
+	 * Don't go beyond strlen(entry->log).
+	 */
+	entry->size = len + tomoyo_round2(sizeof(*entry));
+	spin_lock(&tomoyo_log_lock);
+	if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] &&
+	    tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >=
+	    tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) {
+		quota_exceeded = true;
+	} else {
+		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size;
+		list_add_tail(&entry->list, &tomoyo_log);
+		tomoyo_log_count++;
+	}
+	spin_unlock(&tomoyo_log_lock);
+	if (quota_exceeded) {
+		kfree(buf);
+		kfree(entry);
+		goto out;
+	}
+	wake_up(&tomoyo_log_wait);
+out:
+	return;
+}
+
+/**
+ * tomoyo_write_log - Write an audit log.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ *
+ * Returns nothing.
+ */
+void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+	va_list args;
+	int len;
+	va_start(args, fmt);
+	len = vsnprintf((char *) &len, 1, fmt, args) + 1;
+	va_end(args);
+	va_start(args, fmt);
+	tomoyo_write_log2(r, len, fmt, args);
+	va_end(args);
+}
+
+/**
+ * tomoyo_read_log - Read an audit log.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+void tomoyo_read_log(struct tomoyo_io_buffer *head)
+{
+	struct tomoyo_log *ptr = NULL;
+	if (head->r.w_pos)
+		return;
+	kfree(head->read_buf);
+	head->read_buf = NULL;
+	spin_lock(&tomoyo_log_lock);
+	if (!list_empty(&tomoyo_log)) {
+		ptr = list_entry(tomoyo_log.next, typeof(*ptr), list);
+		list_del(&ptr->list);
+		tomoyo_log_count--;
+		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size;
+	}
+	spin_unlock(&tomoyo_log_lock);
+	if (ptr) {
+		head->read_buf = ptr->log;
+		head->r.w[head->r.w_pos++] = head->read_buf;
+		kfree(ptr);
+	}
+}
+
+/**
+ * tomoyo_poll_log - Wait for an audit log.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table". Maybe NULL.
+ *
+ * Returns POLLIN | POLLRDNORM when ready to read an audit log.
+ */
+unsigned int tomoyo_poll_log(struct file *file, poll_table *wait)
+{
+	if (tomoyo_log_count)
+		return POLLIN | POLLRDNORM;
+	poll_wait(file, &tomoyo_log_wait, wait);
+	if (tomoyo_log_count)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/common.c b/ap/os/linux/linux-3.4.x/security/tomoyo/common.c
new file mode 100644
index 0000000..8656b16
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/common.c
@@ -0,0 +1,2806 @@
+/*
+ * security/tomoyo/common.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+#include "common.h"
+
+/* 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"
+};
+
+/* String table for /sys/kernel/security/tomoyo/profile */
+const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+				       + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+	/* CONFIG::file group */
+	[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",
+	/* CONFIG::network group */
+	[TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
+	[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
+	[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
+	[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
+	[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
+	[TOMOYO_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
+	[TOMOYO_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
+	[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
+	[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
+	[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
+	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
+	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
+	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
+	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
+	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
+	/* CONFIG::misc group */
+	[TOMOYO_MAC_ENVIRON] = "env",
+	/* CONFIG group */
+	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
+	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network",
+	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc",
+};
+
+/* String table for conditions. */
+const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
+	[TOMOYO_TASK_UID]             = "task.uid",
+	[TOMOYO_TASK_EUID]            = "task.euid",
+	[TOMOYO_TASK_SUID]            = "task.suid",
+	[TOMOYO_TASK_FSUID]           = "task.fsuid",
+	[TOMOYO_TASK_GID]             = "task.gid",
+	[TOMOYO_TASK_EGID]            = "task.egid",
+	[TOMOYO_TASK_SGID]            = "task.sgid",
+	[TOMOYO_TASK_FSGID]           = "task.fsgid",
+	[TOMOYO_TASK_PID]             = "task.pid",
+	[TOMOYO_TASK_PPID]            = "task.ppid",
+	[TOMOYO_EXEC_ARGC]            = "exec.argc",
+	[TOMOYO_EXEC_ENVC]            = "exec.envc",
+	[TOMOYO_TYPE_IS_SOCKET]       = "socket",
+	[TOMOYO_TYPE_IS_SYMLINK]      = "symlink",
+	[TOMOYO_TYPE_IS_FILE]         = "file",
+	[TOMOYO_TYPE_IS_BLOCK_DEV]    = "block",
+	[TOMOYO_TYPE_IS_DIRECTORY]    = "directory",
+	[TOMOYO_TYPE_IS_CHAR_DEV]     = "char",
+	[TOMOYO_TYPE_IS_FIFO]         = "fifo",
+	[TOMOYO_MODE_SETUID]          = "setuid",
+	[TOMOYO_MODE_SETGID]          = "setgid",
+	[TOMOYO_MODE_STICKY]          = "sticky",
+	[TOMOYO_MODE_OWNER_READ]      = "owner_read",
+	[TOMOYO_MODE_OWNER_WRITE]     = "owner_write",
+	[TOMOYO_MODE_OWNER_EXECUTE]   = "owner_execute",
+	[TOMOYO_MODE_GROUP_READ]      = "group_read",
+	[TOMOYO_MODE_GROUP_WRITE]     = "group_write",
+	[TOMOYO_MODE_GROUP_EXECUTE]   = "group_execute",
+	[TOMOYO_MODE_OTHERS_READ]     = "others_read",
+	[TOMOYO_MODE_OTHERS_WRITE]    = "others_write",
+	[TOMOYO_MODE_OTHERS_EXECUTE]  = "others_execute",
+	[TOMOYO_EXEC_REALPATH]        = "exec.realpath",
+	[TOMOYO_SYMLINK_TARGET]       = "symlink.target",
+	[TOMOYO_PATH1_UID]            = "path1.uid",
+	[TOMOYO_PATH1_GID]            = "path1.gid",
+	[TOMOYO_PATH1_INO]            = "path1.ino",
+	[TOMOYO_PATH1_MAJOR]          = "path1.major",
+	[TOMOYO_PATH1_MINOR]          = "path1.minor",
+	[TOMOYO_PATH1_PERM]           = "path1.perm",
+	[TOMOYO_PATH1_TYPE]           = "path1.type",
+	[TOMOYO_PATH1_DEV_MAJOR]      = "path1.dev_major",
+	[TOMOYO_PATH1_DEV_MINOR]      = "path1.dev_minor",
+	[TOMOYO_PATH2_UID]            = "path2.uid",
+	[TOMOYO_PATH2_GID]            = "path2.gid",
+	[TOMOYO_PATH2_INO]            = "path2.ino",
+	[TOMOYO_PATH2_MAJOR]          = "path2.major",
+	[TOMOYO_PATH2_MINOR]          = "path2.minor",
+	[TOMOYO_PATH2_PERM]           = "path2.perm",
+	[TOMOYO_PATH2_TYPE]           = "path2.type",
+	[TOMOYO_PATH2_DEV_MAJOR]      = "path2.dev_major",
+	[TOMOYO_PATH2_DEV_MINOR]      = "path2.dev_minor",
+	[TOMOYO_PATH1_PARENT_UID]     = "path1.parent.uid",
+	[TOMOYO_PATH1_PARENT_GID]     = "path1.parent.gid",
+	[TOMOYO_PATH1_PARENT_INO]     = "path1.parent.ino",
+	[TOMOYO_PATH1_PARENT_PERM]    = "path1.parent.perm",
+	[TOMOYO_PATH2_PARENT_UID]     = "path2.parent.uid",
+	[TOMOYO_PATH2_PARENT_GID]     = "path2.parent.gid",
+	[TOMOYO_PATH2_PARENT_INO]     = "path2.parent.ino",
+	[TOMOYO_PATH2_PARENT_PERM]    = "path2.parent.perm",
+};
+
+/* String table for PREFERENCE keyword. */
+static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
+	[TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
+	[TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
+};
+
+/* 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 socket's operation. */
+const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = {
+	[TOMOYO_NETWORK_BIND]    = "bind",
+	[TOMOYO_NETWORK_LISTEN]  = "listen",
+	[TOMOYO_NETWORK_CONNECT] = "connect",
+	[TOMOYO_NETWORK_SEND]    = "send",
+};
+
+/* String table for categories. */
+static const char * const tomoyo_category_keywords
+[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+	[TOMOYO_MAC_CATEGORY_FILE]    = "file",
+	[TOMOYO_MAC_CATEGORY_NETWORK] = "network",
+	[TOMOYO_MAC_CATEGORY_MISC]    = "misc",
+};
+
+/* Permit policy management by non-root user? */
+static bool tomoyo_manage_by_non_root;
+
+/* Utility functions. */
+
+/**
+ * tomoyo_yesno - Return "yes" or "no".
+ *
+ * @value: Bool value.
+ */
+const char *tomoyo_yesno(const unsigned int value)
+{
+	return value ? "yes" : "no";
+}
+
+/**
+ * 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.
+ */
+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);
+}
+
+/**
+ * tomoyo_flush - Flush queued string to userspace's buffer.
+ *
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true if all data was flushed, false otherwise.
+ */
+static bool tomoyo_flush(struct tomoyo_io_buffer *head)
+{
+	while (head->r.w_pos) {
+		const char *w = head->r.w[0];
+		size_t len = strlen(w);
+		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;
+		}
+		head->r.w[0] = w;
+		if (*w)
+			return false;
+		/* Add '\0' for audit logs and query. */
+		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;
+}
+
+/**
+ * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
+ *
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ * @string: String to print.
+ *
+ * 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.
+ */
+static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
+{
+	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);
+}
+
+static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
+			     ...) __printf(2, 3);
+
+/**
+ * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @fmt:  The printf()'s format string, followed by parameters.
+ */
+static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
+			     ...)
+{
+	va_list args;
+	size_t len;
+	size_t pos = head->r.avail;
+	int size = head->readbuf_size - pos;
+	if (size <= 0)
+		return;
+	va_start(args, fmt);
+	len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
+	va_end(args);
+	if (pos + len >= head->readbuf_size) {
+		WARN_ON(1);
+		return;
+	}
+	head->r.avail += len;
+	tomoyo_set_string(head, head->read_buf + pos);
+}
+
+/**
+ * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_set_space(struct tomoyo_io_buffer *head)
+{
+	tomoyo_set_string(head, " ");
+}
+
+/**
+ * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
+{
+	tomoyo_set_string(head, "\n");
+	return !head->r.w_pos;
+}
+
+/**
+ * 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, "/");
+}
+
+/* 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 = 20110903;
+	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);
+}
+
+/**
+ * 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);
+	if (ptr->group) {
+		tomoyo_set_string(head, "@");
+		tomoyo_set_string(head, ptr->group->group_name->name);
+	} else {
+		tomoyo_set_string(head, ptr->filename->name);
+	}
+}
+
+/**
+ * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_name_union".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head,
+					   const struct tomoyo_name_union *ptr)
+{
+	if (ptr->group) {
+		tomoyo_set_string(head, "@");
+		tomoyo_set_string(head, ptr->group->group_name->name);
+	} else {
+		tomoyo_set_string(head, "\"");
+		tomoyo_set_string(head, ptr->filename->name);
+		tomoyo_set_string(head, "\"");
+	}
+}
+
+/**
+ * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_number_union".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_number_union_nospace
+(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
+{
+	if (ptr->group) {
+		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];
+		u8 min_type = ptr->value_type[0];
+		const u8 max_type = ptr->value_type[1];
+		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);
+	}
+}
+
+/**
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_number_union".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+				      const struct tomoyo_number_union *ptr)
+{
+	tomoyo_set_space(head);
+	tomoyo_print_number_union_nospace(head, ptr);
+}
+
+/**
+ * tomoyo_assign_profile - Create a new profile.
+ *
+ * @ns:      Pointer to "struct tomoyo_policy_namespace".
+ * @profile: Profile number to create.
+ *
+ * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
+ */
+static struct tomoyo_profile *tomoyo_assign_profile
+(struct tomoyo_policy_namespace *ns, const unsigned int profile)
+{
+	struct tomoyo_profile *ptr;
+	struct tomoyo_profile *entry;
+	if (profile >= TOMOYO_MAX_PROFILES)
+		return NULL;
+	ptr = ns->profile_ptr[profile];
+	if (ptr)
+		return ptr;
+	entry = kzalloc(sizeof(*entry), GFP_NOFS);
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	ptr = ns->profile_ptr[profile];
+	if (!ptr && tomoyo_memory_ok(entry)) {
+		ptr = entry;
+		ptr->default_config = TOMOYO_CONFIG_DISABLED |
+			TOMOYO_CONFIG_WANT_GRANT_LOG |
+			TOMOYO_CONFIG_WANT_REJECT_LOG;
+		memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
+		       sizeof(ptr->config));
+		ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] =
+			CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG;
+		ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] =
+			CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY;
+		mb(); /* Avoid out-of-order execution. */
+		ns->profile_ptr[profile] = ptr;
+		entry = NULL;
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+ out:
+	kfree(entry);
+	return ptr;
+}
+
+/**
+ * tomoyo_profile - Find a profile.
+ *
+ * @ns:      Pointer to "struct tomoyo_policy_namespace".
+ * @profile: Profile number to find.
+ *
+ * Returns pointer to "struct tomoyo_profile".
+ */
+struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
+				      const u8 profile)
+{
+	static struct tomoyo_profile tomoyo_null_profile;
+	struct tomoyo_profile *ptr = ns->profile_ptr[profile];
+	if (!ptr)
+		ptr = &tomoyo_null_profile;
+	return ptr;
+}
+
+/**
+ * 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.
+ */
+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;
+}
+
+/**
+ * tomoyo_set_uint - Set value for specified preference.
+ *
+ * @i:      Pointer to "unsigned int".
+ * @string: String to check.
+ * @find:   Name of keyword.
+ *
+ * Returns nothing.
+ */
+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);
+}
+
+/**
+ * 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.
+ */
+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++) {
+			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]))
+				continue;
+			config = profile->config[i];
+			break;
+		}
+		if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+			return -EINVAL;
+	} else {
+		return -EINVAL;
+	}
+	if (strstr(value, "use_default")) {
+		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;
+		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;
+			}
+		}
+	}
+	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;
+}
+
+/**
+ * tomoyo_write_profile - Write profile table.
+ *
+ * @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;
+	if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
+	    == 1)
+		return 0;
+	i = simple_strtoul(data, &cp, 10);
+	if (*cp != '-')
+		return -EINVAL;
+	data = cp + 1;
+	profile = tomoyo_assign_profile(head->w.ns, i);
+	if (!profile)
+		return -EINVAL;
+	cp = strchr(data, '=');
+	if (!cp)
+		return -EINVAL;
+	*cp++ = '\0';
+	if (!strcmp(data, "COMMENT")) {
+		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);
+		tomoyo_put_name(old_comment);
+		return 0;
+	}
+	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;
+	}
+	return tomoyo_set_mode(data, cp, profile);
+}
+
+/**
+ * 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.
+ */
+static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
+{
+	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));
+}
+
+/**
+ * tomoyo_read_profile - Read profile table.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
+{
+	u8 index;
+	struct tomoyo_policy_namespace *ns =
+		container_of(head->r.ns, typeof(*ns), namespace_list);
+	const struct tomoyo_profile *profile;
+	if (head->r.eof)
+		return;
+ next:
+	index = head->r.index;
+	profile = ns->profile_ptr[index];
+	switch (head->r.step) {
+	case 0:
+		tomoyo_print_namespace(head);
+		tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
+				 ns->profile_version);
+		head->r.step++;
+		break;
+	case 1:
+		for ( ; head->r.index < TOMOYO_MAX_PROFILES;
+		      head->r.index++)
+			if (ns->profile_ptr[head->r.index])
+				break;
+		if (head->r.index == TOMOYO_MAX_PROFILES) {
+			head->r.eof = true;
+			return;
+		}
+		head->r.step++;
+		break;
+	case 2:
+		{
+			u8 i;
+			const struct tomoyo_path_info *comment =
+				profile->comment;
+			tomoyo_print_namespace(head);
+			tomoyo_io_printf(head, "%u-COMMENT=", index);
+			tomoyo_set_string(head, comment ? comment->name : "");
+			tomoyo_set_lf(head);
+			tomoyo_print_namespace(head);
+			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");
+			head->r.step++;
+		}
+		break;
+	case 3:
+		{
+			tomoyo_print_namespace(head);
+			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];
+			if (config == TOMOYO_CONFIG_USE_DEFAULT)
+				continue;
+			tomoyo_print_namespace(head);
+			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]);
+			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;
+		}
+		break;
+	}
+	if (tomoyo_flush(head))
+		goto next;
+}
+
+/**
+ * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
+				const struct tomoyo_acl_head *b)
+{
+	return container_of(a, struct tomoyo_manager, head)->manager ==
+		container_of(b, struct tomoyo_manager, head)->manager;
+}
+
+/**
+ * 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.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_manager_entry(const char *manager,
+				       const bool is_delete)
+{
+	struct tomoyo_manager e = { };
+	struct tomoyo_acl_param param = {
+		/* .ns = &tomoyo_kernel_namespace, */
+		.is_delete = is_delete,
+		.list = &tomoyo_kernel_namespace.
+		policy_list[TOMOYO_ID_MANAGER],
+	};
+	int error = is_delete ? -ENOENT : -ENOMEM;
+	if (tomoyo_domain_def(manager)) {
+		if (!tomoyo_correct_domain(manager))
+			return -EINVAL;
+		e.is_domain = true;
+	} else {
+		if (!tomoyo_correct_path(manager))
+			return -EINVAL;
+	}
+	e.manager = tomoyo_get_name(manager);
+	if (e.manager) {
+		error = tomoyo_update_policy(&e.head, sizeof(e), &param,
+					     tomoyo_same_manager);
+		tomoyo_put_name(e.manager);
+	}
+	return error;
+}
+
+/**
+ * tomoyo_write_manager - Write manager policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
+{
+	char *data = head->write_buf;
+
+	if (!strcmp(data, "manage_by_non_root")) {
+		tomoyo_manage_by_non_root = !head->w.is_delete;
+		return 0;
+	}
+	return tomoyo_update_manager_entry(data, head->w.is_delete);
+}
+
+/**
+ * tomoyo_read_manager - Read manager policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
+{
+	if (head->r.eof)
+		return;
+	list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.
+			     policy_list[TOMOYO_ID_MANAGER]) {
+		struct tomoyo_manager *ptr =
+			list_entry(head->r.acl, typeof(*ptr), head.list);
+		if (ptr->head.is_deleted)
+			continue;
+		if (!tomoyo_flush(head))
+			return;
+		tomoyo_set_string(head, ptr->manager->name);
+		tomoyo_set_lf(head);
+	}
+	head->r.eof = true;
+}
+
+/**
+ * tomoyo_manager - Check whether the current process is a policy manager.
+ *
+ * Returns true if the current process is permitted to modify policy
+ * via /sys/kernel/security/tomoyo/ interface.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_manager(void)
+{
+	struct tomoyo_manager *ptr;
+	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;
+	list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
+				policy_list[TOMOYO_ID_MANAGER], head.list) {
+		if (!ptr->head.is_deleted && ptr->is_domain
+		    && !tomoyo_pathcmp(domainname, ptr->manager)) {
+			found = true;
+			break;
+		}
+	}
+	if (found)
+		return true;
+	exe = tomoyo_get_exe();
+	if (!exe)
+		return false;
+	list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
+				policy_list[TOMOYO_ID_MANAGER], head.list) {
+		if (!ptr->head.is_deleted && !ptr->is_domain
+		    && !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;
+		}
+	}
+	kfree(exe);
+	return found;
+}
+
+static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
+(unsigned int serial);
+
+/**
+ * tomoyo_select_domain - Parse select command.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @data: String to parse.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
+				 const char *data)
+{
+	unsigned int pid;
+	struct tomoyo_domain_info *domain = NULL;
+	bool global_pid = false;
+	if (strncmp(data, "select ", 7))
+		return false;
+	data += 7;
+	if (sscanf(data, "pid=%u", &pid) == 1 ||
+	    (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
+		struct task_struct *p;
+		rcu_read_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);
+		rcu_read_unlock();
+	} else if (!strncmp(data, "domain=", 7)) {
+		if (tomoyo_domain_def(data + 7))
+			domain = tomoyo_find_domain(data + 7);
+	} else if (sscanf(data, "Q=%u", &pid) == 1) {
+		domain = tomoyo_find_domain_by_qid(pid);
+	} else
+		return false;
+	head->w.domain = domain;
+	/* Accessing read_buf is safe because head->io_sem is held. */
+	if (!head->read_buf)
+		return true; /* Do nothing if open(O_WRONLY). */
+	memset(&head->r, 0, sizeof(head->r));
+	head->r.print_this_domain_only = true;
+	if (domain)
+		head->r.domain = &domain->list;
+	else
+		head->r.eof = 1;
+	tomoyo_io_printf(head, "# select %s\n", data);
+	if (domain && domain->is_deleted)
+		tomoyo_io_printf(head, "# This is a deleted domain.\n");
+	return true;
+}
+
+/**
+ * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
+			      const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
+	return p1->domainname == p2->domainname;
+}
+
+/**
+ * tomoyo_write_task - Update task related list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_task(struct tomoyo_acl_param *param)
+{
+	int error = -EINVAL;
+	if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
+		struct tomoyo_task_acl e = {
+			.head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
+			.domainname = tomoyo_get_domainname(param),
+		};
+		if (e.domainname)
+			error = tomoyo_update_domain(&e.head, sizeof(e), param,
+						     tomoyo_same_task_acl,
+						     NULL);
+		tomoyo_put_name(e.domainname);
+	}
+	return error;
+}
+
+/**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+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);
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		return -EINTR;
+	/* Is there an active domain? */
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+		/* 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;
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+	return 0;
+}
+
+/**
+ * tomoyo_write_domain2 - Write domain policy.
+ *
+ * @ns:        Pointer to "struct tomoyo_policy_namespace".
+ * @list:      Pointer to "struct list_head".
+ * @data:      Policy to be interpreted.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
+				struct list_head *list, char *data,
+				const bool is_delete)
+{
+	struct tomoyo_acl_param param = {
+		.ns = ns,
+		.list = list,
+		.data = data,
+		.is_delete = is_delete,
+	};
+	static const struct {
+		const char *keyword;
+		int (*write) (struct tomoyo_acl_param *);
+	} tomoyo_callback[5] = {
+		{ "file ", tomoyo_write_file },
+		{ "network inet ", tomoyo_write_inet_network },
+		{ "network unix ", tomoyo_write_unix_network },
+		{ "misc ", tomoyo_write_misc },
+		{ "task ", tomoyo_write_task },
+	};
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) {
+		if (!tomoyo_str_starts(&param.data,
+				       tomoyo_callback[i].keyword))
+			continue;
+		return tomoyo_callback[i].write(&param);
+	}
+	return -EINVAL;
+}
+
+/* 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",
+};
+
+/**
+ * tomoyo_write_domain - Write domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
+{
+	char *data = head->write_buf;
+	struct tomoyo_policy_namespace *ns;
+	struct tomoyo_domain_info *domain = head->w.domain;
+	const bool is_delete = head->w.is_delete;
+	bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
+	unsigned int profile;
+	if (*data == '<') {
+		int ret = 0;
+		domain = NULL;
+		if (is_delete)
+			ret = tomoyo_delete_domain(data);
+		else if (is_select)
+			domain = tomoyo_find_domain(data);
+		else
+			domain = tomoyo_assign_domain(data, false);
+		head->w.domain = domain;
+		return ret;
+	}
+	if (!domain)
+		return -EINVAL;
+	ns = domain->ns;
+	if (sscanf(data, "use_profile %u", &profile) == 1
+	    && profile < TOMOYO_MAX_PROFILES) {
+		if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
+			domain->profile = (u8) profile;
+		return 0;
+	}
+	if (sscanf(data, "use_group %u\n", &profile) == 1
+	    && profile < TOMOYO_MAX_ACL_GROUPS) {
+		if (!is_delete)
+			domain->group = (u8) profile;
+		return 0;
+	}
+	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;
+		return 0;
+	}
+	return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
+				    is_delete);
+}
+
+/**
+ * tomoyo_print_condition - Print condition part.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @cond: Pointer to "struct tomoyo_condition".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
+				   const struct tomoyo_condition *cond)
+{
+	switch (head->r.cond_step) {
+	case 0:
+		head->r.cond_index = 0;
+		head->r.cond_step++;
+		if (cond->transit) {
+			tomoyo_set_space(head);
+			tomoyo_set_string(head, cond->transit->name);
+		}
+		/* fall through */
+	case 1:
+		{
+			const u16 condc = cond->condc;
+			const struct tomoyo_condition_element *condp =
+				(typeof(condp)) (cond + 1);
+			const struct tomoyo_number_union *numbers_p =
+				(typeof(numbers_p)) (condp + condc);
+			const struct tomoyo_name_union *names_p =
+				(typeof(names_p))
+				(numbers_p + cond->numbers_count);
+			const struct tomoyo_argv *argv =
+				(typeof(argv)) (names_p + cond->names_count);
+			const struct tomoyo_envp *envp =
+				(typeof(envp)) (argv + cond->argc);
+			u16 skip;
+			for (skip = 0; skip < head->r.cond_index; skip++) {
+				const u8 left = condp->left;
+				const u8 right = condp->right;
+				condp++;
+				switch (left) {
+				case TOMOYO_ARGV_ENTRY:
+					argv++;
+					continue;
+				case TOMOYO_ENVP_ENTRY:
+					envp++;
+					continue;
+				case TOMOYO_NUMBER_UNION:
+					numbers_p++;
+					break;
+				}
+				switch (right) {
+				case TOMOYO_NAME_UNION:
+					names_p++;
+					break;
+				case TOMOYO_NUMBER_UNION:
+					numbers_p++;
+					break;
+				}
+			}
+			while (head->r.cond_index < condc) {
+				const u8 match = condp->equals;
+				const u8 left = condp->left;
+				const u8 right = condp->right;
+				if (!tomoyo_flush(head))
+					return false;
+				condp++;
+				head->r.cond_index++;
+				tomoyo_set_space(head);
+				switch (left) {
+				case TOMOYO_ARGV_ENTRY:
+					tomoyo_io_printf(head,
+							 "exec.argv[%lu]%s=\"",
+							 argv->index, argv->
+							 is_not ? "!" : "");
+					tomoyo_set_string(head,
+							  argv->value->name);
+					tomoyo_set_string(head, "\"");
+					argv++;
+					continue;
+				case TOMOYO_ENVP_ENTRY:
+					tomoyo_set_string(head,
+							  "exec.envp[\"");
+					tomoyo_set_string(head,
+							  envp->name->name);
+					tomoyo_io_printf(head, "\"]%s=", envp->
+							 is_not ? "!" : "");
+					if (envp->value) {
+						tomoyo_set_string(head, "\"");
+						tomoyo_set_string(head, envp->
+								  value->name);
+						tomoyo_set_string(head, "\"");
+					} else {
+						tomoyo_set_string(head,
+								  "NULL");
+					}
+					envp++;
+					continue;
+				case TOMOYO_NUMBER_UNION:
+					tomoyo_print_number_union_nospace
+						(head, numbers_p++);
+					break;
+				default:
+					tomoyo_set_string(head,
+					       tomoyo_condition_keyword[left]);
+					break;
+				}
+				tomoyo_set_string(head, match ? "=" : "!=");
+				switch (right) {
+				case TOMOYO_NAME_UNION:
+					tomoyo_print_name_union_quoted
+						(head, names_p++);
+					break;
+				case TOMOYO_NUMBER_UNION:
+					tomoyo_print_number_union_nospace
+						(head, numbers_p++);
+					break;
+				default:
+					tomoyo_set_string(head,
+					  tomoyo_condition_keyword[right]);
+					break;
+				}
+			}
+		}
+		head->r.cond_step++;
+		/* fall through */
+	case 2:
+		if (!tomoyo_flush(head))
+			break;
+		head->r.cond_step++;
+		/* fall through */
+	case 3:
+		if (cond->grant_log != TOMOYO_GRANTLOG_AUTO)
+			tomoyo_io_printf(head, " grant_log=%s",
+					 tomoyo_yesno(cond->grant_log ==
+						      TOMOYO_GRANTLOG_YES));
+		tomoyo_set_lf(head);
+		return true;
+	}
+	return false;
+}
+
+/**
+ * tomoyo_set_group - Print "acl_group " header keyword and category name.
+ *
+ * @head:     Pointer to "struct tomoyo_io_buffer".
+ * @category: Category name.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_set_group(struct tomoyo_io_buffer *head,
+			     const char *category)
+{
+	if (head->type == TOMOYO_EXCEPTIONPOLICY) {
+		tomoyo_print_namespace(head);
+		tomoyo_io_printf(head, "acl_group %u ",
+				 head->r.acl_group_index);
+	}
+	tomoyo_set_string(head, category);
+}
+
+/**
+ * tomoyo_print_entry - Print an ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @acl:  Pointer to an ACL entry.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
+			       struct tomoyo_acl_info *acl)
+{
+	const u8 acl_type = acl->type;
+	bool first = true;
+	u8 bit;
+
+	if (head->r.print_cond_part)
+		goto print_cond_part;
+	if (acl->is_deleted)
+		return true;
+	if (!tomoyo_flush(head))
+		return false;
+	else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
+		struct tomoyo_path_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		const u16 perm = ptr->perm;
+		for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
+			if (!(perm & (1 << bit)))
+				continue;
+			if (head->r.print_transition_related_only &&
+			    bit != TOMOYO_TYPE_EXECUTE)
+				continue;
+			if (first) {
+				tomoyo_set_group(head, "file ");
+				first = false;
+			} else {
+				tomoyo_set_slash(head);
+			}
+			tomoyo_set_string(head, tomoyo_path_keyword[bit]);
+		}
+		if (first)
+			return true;
+		tomoyo_print_name_union(head, &ptr->name);
+	} else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
+		struct tomoyo_task_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		tomoyo_set_group(head, "task ");
+		tomoyo_set_string(head, "manual_domain_transition ");
+		tomoyo_set_string(head, ptr->domainname->name);
+	} else if (head->r.print_transition_related_only) {
+		return true;
+	} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
+		struct tomoyo_path2_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		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;
+		tomoyo_print_name_union(head, &ptr->name1);
+		tomoyo_print_name_union(head, &ptr->name2);
+	} else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
+		struct tomoyo_path_number_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		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;
+		tomoyo_print_name_union(head, &ptr->name);
+		tomoyo_print_number_union(head, &ptr->number);
+	} else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
+		struct tomoyo_mkdev_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		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;
+		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);
+	} else if (acl_type == TOMOYO_TYPE_INET_ACL) {
+		struct tomoyo_inet_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		const u8 perm = ptr->perm;
+
+		for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
+			if (!(perm & (1 << bit)))
+				continue;
+			if (first) {
+				tomoyo_set_group(head, "network inet ");
+				tomoyo_set_string(head, tomoyo_proto_keyword
+						  [ptr->protocol]);
+				tomoyo_set_space(head);
+				first = false;
+			} else {
+				tomoyo_set_slash(head);
+			}
+			tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
+		}
+		if (first)
+			return true;
+		tomoyo_set_space(head);
+		if (ptr->address.group) {
+			tomoyo_set_string(head, "@");
+			tomoyo_set_string(head, ptr->address.group->group_name
+					  ->name);
+		} else {
+			char buf[128];
+			tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
+			tomoyo_io_printf(head, "%s", buf);
+		}
+		tomoyo_print_number_union(head, &ptr->port);
+	} else if (acl_type == TOMOYO_TYPE_UNIX_ACL) {
+		struct tomoyo_unix_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		const u8 perm = ptr->perm;
+
+		for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
+			if (!(perm & (1 << bit)))
+				continue;
+			if (first) {
+				tomoyo_set_group(head, "network unix ");
+				tomoyo_set_string(head, tomoyo_proto_keyword
+						  [ptr->protocol]);
+				tomoyo_set_space(head);
+				first = false;
+			} else {
+				tomoyo_set_slash(head);
+			}
+			tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
+		}
+		if (first)
+			return true;
+		tomoyo_print_name_union(head, &ptr->name);
+	} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
+		struct tomoyo_mount_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+		tomoyo_set_group(head, "file mount");
+		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);
+	} else if (acl_type == TOMOYO_TYPE_ENV_ACL) {
+		struct tomoyo_env_acl *ptr =
+			container_of(acl, typeof(*ptr), head);
+
+		tomoyo_set_group(head, "misc env ");
+		tomoyo_set_string(head, ptr->env->name);
+	}
+	if (acl->cond) {
+		head->r.print_cond_part = true;
+		head->r.cond_step = 0;
+		if (!tomoyo_flush(head))
+			return false;
+print_cond_part:
+		if (!tomoyo_print_condition(head, acl->cond))
+			return false;
+		head->r.print_cond_part = false;
+	} else {
+		tomoyo_set_lf(head);
+	}
+	return true;
+}
+
+/**
+ * tomoyo_read_domain2 - Read domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @list: Pointer to "struct list_head".
+ *
+ * Caller holds tomoyo_read_lock().
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
+				struct list_head *list)
+{
+	list_for_each_cookie(head->r.acl, list) {
+		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;
+	return true;
+}
+
+/**
+ * tomoyo_read_domain - Read domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
+{
+	if (head->r.eof)
+		return;
+	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
+		struct tomoyo_domain_info *domain =
+			list_entry(head->r.domain, typeof(*domain), list);
+		switch (head->r.step) {
+			u8 i;
+		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);
+			tomoyo_io_printf(head, "use_profile %u\n",
+					 domain->profile);
+			tomoyo_io_printf(head, "use_group %u\n",
+					 domain->group);
+			for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
+				if (domain->flags[i])
+					tomoyo_set_string(head, tomoyo_dif[i]);
+			head->r.step++;
+			tomoyo_set_lf(head);
+			/* fall through */
+		case 1:
+			if (!tomoyo_read_domain2(head, &domain->acl_info_list))
+				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;
+		}
+	}
+ done:
+	head->r.eof = true;
+}
+
+/**
+ * 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)
+{
+	head->r.eof = false;
+	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.
+ */
+static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
+{
+	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). */
+	}
+	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();
+	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);
+	rcu_read_unlock();
+	if (!domain)
+		return;
+	tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
+	tomoyo_set_string(head, domain->domainname->name);
+}
+
+/* String table for domain transition control keywords. */
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+	[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 ",
+};
+
+/* String table for grouping keywords. */
+static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
+	[TOMOYO_PATH_GROUP]    = "path_group ",
+	[TOMOYO_NUMBER_GROUP]  = "number_group ",
+	[TOMOYO_ADDRESS_GROUP] = "address_group ",
+};
+
+/**
+ * tomoyo_write_exception - Write exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
+{
+	const bool is_delete = head->w.is_delete;
+	struct tomoyo_acl_param param = {
+		.ns = head->w.ns,
+		.is_delete = is_delete,
+		.data = head->write_buf,
+	};
+	u8 i;
+	if (tomoyo_str_starts(&param.data, "aggregator "))
+		return tomoyo_write_aggregator(&param);
+	for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
+		if (tomoyo_str_starts(&param.data, tomoyo_transition_type[i]))
+			return tomoyo_write_transition_control(&param, i);
+	for (i = 0; i < TOMOYO_MAX_GROUP; i++)
+		if (tomoyo_str_starts(&param.data, tomoyo_group_name[i]))
+			return tomoyo_write_group(&param, i);
+	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++ == ' ')
+			return tomoyo_write_domain2
+				(head->w.ns, &head->w.ns->acl_group[group],
+				 data, is_delete);
+	}
+	return -EINVAL;
+}
+
+/**
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" 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_group(struct tomoyo_io_buffer *head, const int idx)
+{
+	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) {
+		struct tomoyo_group *group =
+			list_entry(head->r.group, typeof(*group), head.list);
+		list_for_each_cookie(head->r.acl, &group->member_list) {
+			struct tomoyo_acl_head *ptr =
+				list_entry(head->r.acl, typeof(*ptr), list);
+			if (ptr->is_deleted)
+				continue;
+			if (!tomoyo_flush(head))
+				return false;
+			tomoyo_print_namespace(head);
+			tomoyo_set_string(head, tomoyo_group_name[idx]);
+			tomoyo_set_string(head, group->group_name->name);
+			if (idx == TOMOYO_PATH_GROUP) {
+				tomoyo_set_space(head);
+				tomoyo_set_string(head, container_of
+					       (ptr, struct tomoyo_path_group,
+						head)->member_name->name);
+			} else if (idx == TOMOYO_NUMBER_GROUP) {
+				tomoyo_print_number_union(head, &container_of
+							  (ptr,
+						   struct tomoyo_number_group,
+							   head)->number);
+			} else if (idx == TOMOYO_ADDRESS_GROUP) {
+				char buffer[128];
+
+				struct tomoyo_address_group *member =
+					container_of(ptr, typeof(*member),
+						     head);
+				tomoyo_print_ip(buffer, sizeof(buffer),
+						&member->address);
+				tomoyo_io_printf(head, " %s", buffer);
+			}
+			tomoyo_set_lf(head);
+		}
+		head->r.acl = NULL;
+	}
+	head->r.group = NULL;
+	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)
+{
+	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) {
+		struct tomoyo_acl_head *acl =
+			container_of(head->r.acl, typeof(*acl), list);
+		if (acl->is_deleted)
+			continue;
+		if (!tomoyo_flush(head))
+			return false;
+		switch (idx) {
+		case TOMOYO_ID_TRANSITION_CONTROL:
+			{
+				struct tomoyo_transition_control *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_print_namespace(head);
+				tomoyo_set_string(head, tomoyo_transition_type
+						  [ptr->type]);
+				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");
+			}
+			break;
+		case TOMOYO_ID_AGGREGATOR:
+			{
+				struct tomoyo_aggregator *ptr =
+					container_of(acl, typeof(*ptr), head);
+				tomoyo_print_namespace(head);
+				tomoyo_set_string(head, "aggregator ");
+				tomoyo_set_string(head,
+						  ptr->original_name->name);
+				tomoyo_set_space(head);
+				tomoyo_set_string(head,
+					       ptr->aggregated_name->name);
+			}
+			break;
+		default:
+			continue;
+		}
+		tomoyo_set_lf(head);
+	}
+	head->r.acl = NULL;
+	return true;
+}
+
+/**
+ * tomoyo_read_exception - Read exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
+{
+	struct tomoyo_policy_namespace *ns =
+		container_of(head->r.ns, typeof(*ns), namespace_list);
+	if (head->r.eof)
+		return;
+	while (head->r.step < TOMOYO_MAX_POLICY &&
+	       tomoyo_read_policy(head, head->r.step))
+		head->r.step++;
+	if (head->r.step < TOMOYO_MAX_POLICY)
+		return;
+	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)
+		return;
+	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;
+		if (!tomoyo_read_domain2(head, &ns->acl_group
+					 [head->r.acl_group_index]))
+			return;
+		head->r.step++;
+	}
+	head->r.eof = true;
+}
+
+/* Wait queue for kernel -> userspace notification. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
+/* Wait queue for userspace -> kernel notification. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait);
+
+/* Structure for query. */
+struct tomoyo_query {
+	struct list_head list;
+	struct tomoyo_domain_info *domain;
+	char *query;
+	size_t query_len;
+	unsigned int serial;
+	u8 timer;
+	u8 answer;
+	u8 retry;
+};
+
+/* The list for "struct tomoyo_query". */
+static LIST_HEAD(tomoyo_query_list);
+
+/* Lock for manipulating tomoyo_query_list. */
+static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+
+/*
+ * Number of "struct file" referring /sys/kernel/security/tomoyo/query
+ * interface.
+ */
+static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
+
+/**
+ * tomoyo_truncate - Truncate a line.
+ *
+ * @str: String to truncate.
+ *
+ * Returns length of truncated @str.
+ */
+static int tomoyo_truncate(char *str)
+{
+	char *start = str;
+	while (*(unsigned char *) str > (unsigned char) ' ')
+		str++;
+	*str = '\0';
+	return strlen(start) + 1;
+}
+
+/**
+ * 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 *realpath = NULL;
+	char *argv0 = NULL;
+	char *symlink = NULL;
+	char *cp = strchr(header, '\n');
+	int len;
+	if (!cp)
+		return;
+	cp = strchr(cp + 1, '\n');
+	if (!cp)
+		return;
+	*cp++ = '\0';
+	len = strlen(cp) + 1;
+	/* strstr() will return NULL if ordering is wrong. */
+	if (*cp == 'f') {
+		argv0 = strstr(header, " argv[]={ \"");
+		if (argv0) {
+			argv0 += 10;
+			len += tomoyo_truncate(argv0) + 14;
+		}
+		realpath = strstr(header, " exec={ realpath=\"");
+		if (realpath) {
+			realpath += 8;
+			len += tomoyo_truncate(realpath) + 6;
+		}
+		symlink = strstr(header, " symlink.target=\"");
+		if (symlink)
+			len += tomoyo_truncate(symlink + 1) + 1;
+	}
+	buffer = kmalloc(len, GFP_NOFS);
+	if (!buffer)
+		return;
+	snprintf(buffer, len - 1, "%s", cp);
+	if (realpath)
+		tomoyo_addprintf(buffer, len, " exec.%s", realpath);
+	if (argv0)
+		tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
+	if (symlink)
+		tomoyo_addprintf(buffer, len, "%s", symlink);
+	tomoyo_normalize_line(buffer);
+	if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
+				  false))
+		tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
+	kfree(buffer);
+}
+
+/**
+ * tomoyo_supervisor - Ask for the supervisor's decision.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ *
+ * 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;
+	int error;
+	int len;
+	static unsigned int tomoyo_serial;
+	struct tomoyo_query entry = { };
+	bool quota_exceeded = false;
+	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;
+	if (r->mode)
+		tomoyo_update_stat(r->mode);
+	switch (r->mode) {
+	case TOMOYO_CONFIG_ENFORCING:
+		error = -EPERM;
+		if (atomic_read(&tomoyo_query_observers))
+			break;
+		goto out;
+	case TOMOYO_CONFIG_LEARNING:
+		error = 0;
+		/* Check max_learning_entry parameter. */
+		if (tomoyo_domain_quota_is_ok(r))
+			break;
+		/* fall through */
+	default:
+		return 0;
+	}
+	/* Get message. */
+	va_start(args, fmt);
+	entry.query = tomoyo_init_log(r, len, fmt, args);
+	va_end(args);
+	if (!entry.query)
+		goto out;
+	entry.query_len = strlen(entry.query) + 1;
+	if (!error) {
+		tomoyo_add_entry(r->domain, entry.query);
+		goto out;
+	}
+	len = tomoyo_round2(entry.query_len);
+	entry.domain = r->domain;
+	spin_lock(&tomoyo_query_list_lock);
+	if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] &&
+	    tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len
+	    >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) {
+		quota_exceeded = true;
+	} else {
+		entry.serial = tomoyo_serial++;
+		entry.retry = r->retry;
+		tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len;
+		list_add_tail(&entry.list, &tomoyo_query_list);
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (quota_exceeded)
+		goto out;
+	/* Give 10 seconds for supervisor's opinion. */
+	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))
+			break;
+		else
+			entry.timer++;
+	}
+	spin_lock(&tomoyo_query_list_lock);
+	list_del(&entry.list);
+	tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len;
+	spin_unlock(&tomoyo_query_list_lock);
+	switch (entry.answer) {
+	case 3: /* Asked to retry by administrator. */
+		error = TOMOYO_RETRY_REQUEST;
+		r->retry++;
+		break;
+	case 1:
+		/* Granted by administrator. */
+		error = 0;
+		break;
+	default:
+		/* Timed out or rejected by administrator. */
+		break;
+	}
+out:
+	kfree(entry.query);
+	return error;
+}
+
+/**
+ * tomoyo_find_domain_by_qid - Get domain by query id.
+ *
+ * @serial: Query ID assigned by tomoyo_supervisor().
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ */
+static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
+(unsigned int serial)
+{
+	struct tomoyo_query *ptr;
+	struct tomoyo_domain_info *domain = NULL;
+	spin_lock(&tomoyo_query_list_lock);
+	list_for_each_entry(ptr, &tomoyo_query_list, list) {
+		if (ptr->serial != serial)
+			continue;
+		domain = ptr->domain;
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	return domain;
+}
+
+/**
+ * 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 unsigned int tomoyo_poll_query(struct file *file, poll_table *wait)
+{
+	if (!list_empty(&tomoyo_query_list))
+		return POLLIN | POLLRDNORM;
+	poll_wait(file, &tomoyo_query_wait, wait);
+	if (!list_empty(&tomoyo_query_list))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+/**
+ * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ */
+static void tomoyo_read_query(struct tomoyo_io_buffer *head)
+{
+	struct list_head *tmp;
+	unsigned int pos = 0;
+	size_t len = 0;
+	char *buf;
+	if (head->r.w_pos)
+		return;
+	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) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		if (pos++ != head->r.query_index)
+			continue;
+		len = ptr->query_len;
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (!len) {
+		head->r.query_index = 0;
+		return;
+	}
+	buf = kzalloc(len + 32, GFP_NOFS);
+	if (!buf)
+		return;
+	pos = 0;
+	spin_lock(&tomoyo_query_list_lock);
+	list_for_each(tmp, &tomoyo_query_list) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		if (pos++ != head->r.query_index)
+			continue;
+		/*
+		 * Some query can be skipped because tomoyo_query_list
+		 * can change, but I don't care.
+		 */
+		if (len == ptr->query_len)
+			snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
+				 ptr->retry, ptr->query);
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	if (buf[0]) {
+		head->read_buf = buf;
+		head->r.w[head->r.w_pos++] = buf;
+		head->r.query_index++;
+	} 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) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		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) {
+		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+		if (ptr->serial != serial)
+			continue;
+		ptr->answer = answer;
+		/* Remove from tomoyo_query_list. */
+		if (ptr->answer)
+			list_del_init(&ptr->list);
+		break;
+	}
+	spin_unlock(&tomoyo_query_list_lock);
+	return 0;
+}
+
+/**
+ * tomoyo_read_version: Get version.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns version information.
+ */
+static void tomoyo_read_version(struct tomoyo_io_buffer *head)
+{
+	if (!head->r.eof) {
+		tomoyo_io_printf(head, "2.5.0");
+		head->r.eof = true;
+	}
+}
+
+/* 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;
+}
+
+/**
+ * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @type: Type of interface.
+ * @file: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_open_control(const u8 type, struct file *file)
+{
+	struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
+
+	if (!head)
+		return -ENOMEM;
+	mutex_init(&head->io_sem);
+	head->type = type;
+	switch (type) {
+	case TOMOYO_DOMAINPOLICY:
+		/* /sys/kernel/security/tomoyo/domain_policy */
+		head->write = tomoyo_write_domain;
+		head->read = tomoyo_read_domain;
+		break;
+	case TOMOYO_EXCEPTIONPOLICY:
+		/* /sys/kernel/security/tomoyo/exception_policy */
+		head->write = tomoyo_write_exception;
+		head->read = tomoyo_read_exception;
+		break;
+	case TOMOYO_AUDIT:
+		/* /sys/kernel/security/tomoyo/audit */
+		head->poll = tomoyo_poll_log;
+		head->read = tomoyo_read_log;
+		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;
+	case TOMOYO_STAT:
+		/* /sys/kernel/security/tomoyo/stat */
+		head->write = tomoyo_write_stat;
+		head->read = tomoyo_read_stat;
+		head->readbuf_size = 1024;
+		break;
+	case TOMOYO_PROFILE:
+		/* /sys/kernel/security/tomoyo/profile */
+		head->write = tomoyo_write_profile;
+		head->read = tomoyo_read_profile;
+		break;
+	case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
+		head->poll = tomoyo_poll_query;
+		head->write = tomoyo_write_answer;
+		head->read = tomoyo_read_query;
+		break;
+	case TOMOYO_MANAGER:
+		/* /sys/kernel/security/tomoyo/manager */
+		head->write = tomoyo_write_manager;
+		head->read = tomoyo_read_manager;
+		break;
+	}
+	if (!(file->f_mode & FMODE_READ)) {
+		/*
+		 * No need to allocate read_buf since it is not opened
+		 * for reading.
+		 */
+		head->read = NULL;
+		head->poll = NULL;
+	} else if (!head->poll) {
+		/* Don't allocate read_buf for poll() access. */
+		if (!head->readbuf_size)
+			head->readbuf_size = 4096 * 2;
+		head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
+		if (!head->read_buf) {
+			kfree(head);
+			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;
+		head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS);
+		if (!head->write_buf) {
+			kfree(head->read_buf);
+			kfree(head);
+			return -ENOMEM;
+		}
+	}
+	/*
+	 * 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.
+	 */
+	if (type == TOMOYO_QUERY)
+		atomic_inc(&tomoyo_query_observers);
+	file->private_data = head;
+	tomoyo_notify_gc(head, true);
+	return 0;
+}
+
+/**
+ * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table". Maybe NULL.
+ *
+ * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
+ * POLLOUT | POLLWRNORM otherwise.
+ */
+unsigned int tomoyo_poll_control(struct file *file, poll_table *wait)
+{
+	struct tomoyo_io_buffer *head = file->private_data;
+	if (head->poll)
+		return head->poll(file, wait) | POLLOUT | POLLWRNORM;
+	return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
+}
+
+/**
+ * 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;
+}
+
+/**
+ * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @head:       Pointer to "struct tomoyo_io_buffer".
+ * @buffer:     Poiner to buffer to write to.
+ * @buffer_len: Size of @buffer.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
+			    const int buffer_len)
+{
+	int len;
+	int idx;
+
+	if (!head->read)
+		return -ENOSYS;
+	if (mutex_lock_interruptible(&head->io_sem))
+		return -EINTR;
+	head->read_user_buf = buffer;
+	head->read_user_buf_avail = buffer_len;
+	idx = tomoyo_read_lock();
+	if (tomoyo_flush(head))
+		/* Call the policy handler. */
+		do {
+			tomoyo_set_namespace_cursor(head);
+			head->read(head);
+		} while (tomoyo_flush(head) &&
+			 tomoyo_has_more_namespace(head));
+	tomoyo_read_unlock(idx);
+	len = head->read_user_buf - buffer;
+	mutex_unlock(&head->io_sem);
+	return len;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @head:       Pointer to "struct tomoyo_io_buffer".
+ * @buffer:     Pointer to buffer to read from.
+ * @buffer_len: Size of @buffer.
+ *
+ * Returns @buffer_len on success, negative value otherwise.
+ */
+ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
+			     const char __user *buffer, const int buffer_len)
+{
+	int error = buffer_len;
+	size_t avail_len = buffer_len;
+	char *cp0 = head->write_buf;
+	int idx;
+	if (!head->write)
+		return -ENOSYS;
+	if (!access_ok(VERIFY_READ, buffer, buffer_len))
+		return -EFAULT;
+	if (mutex_lock_interruptible(&head->io_sem))
+		return -EINTR;
+	head->read_user_buf_avail = 0;
+	idx = tomoyo_read_lock();
+	/* Read a line and dispatch it to the policy handler. */
+	while (avail_len > 0) {
+		char c;
+		if (head->w.avail >= head->writebuf_size - 1) {
+			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)) {
+			error = -EFAULT;
+			break;
+		}
+		buffer++;
+		avail_len--;
+		cp0[head->w.avail++] = c;
+		if (c != '\n')
+			continue;
+		cp0[head->w.avail - 1] = '\0';
+		head->w.avail = 0;
+		tomoyo_normalize_line(cp0);
+		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;
+		case 0:
+			switch (head->type) {
+			case TOMOYO_DOMAINPOLICY:
+			case TOMOYO_EXCEPTIONPOLICY:
+			case TOMOYO_STAT:
+			case TOMOYO_PROFILE:
+			case TOMOYO_MANAGER:
+				tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
+				break;
+			default:
+				break;
+			}
+			break;
+		}
+	}
+out:
+	tomoyo_read_unlock(idx);
+	mutex_unlock(&head->io_sem);
+	return error;
+}
+
+/**
+ * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_close_control(struct tomoyo_io_buffer *head)
+{
+	/*
+	 * If the file is /sys/kernel/security/tomoyo/query , decrement the
+	 * observer counter.
+	 */
+	if (head->type == TOMOYO_QUERY &&
+	    atomic_dec_and_test(&tomoyo_query_observers))
+		wake_up_all(&tomoyo_answer_wait);
+	tomoyo_notify_gc(head, false);
+	return 0;
+}
+
+/**
+ * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
+ */
+void tomoyo_check_profile(void)
+{
+	struct tomoyo_domain_info *domain;
+	const int idx = tomoyo_read_lock();
+	tomoyo_policy_loaded = true;
+	printk(KERN_INFO "TOMOYO: 2.5.0\n");
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+		const u8 profile = domain->profile;
+		const struct tomoyo_policy_namespace *ns = domain->ns;
+		if (ns->profile_version != 20110903)
+			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
+			continue;
+		printk(KERN_ERR
+		       "Userland tools for TOMOYO 2.5 must be installed and "
+		       "policy must be initialized.\n");
+		printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ "
+		       "for more information.\n");
+		panic("STOP!");
+	}
+	tomoyo_read_unlock(idx);
+	printk(KERN_INFO "Mandatory Access Control activated.\n");
+}
+
+/**
+ * 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);
+#ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+	tomoyo_check_profile();
+#endif
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/common.h b/ap/os/linux/linux-3.4.x/security/tomoyo/common.h
new file mode 100644
index 0000000..30fd983
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/common.h
@@ -0,0 +1,1331 @@
+/*
+ * security/tomoyo/common.h
+ *
+ * Header file for TOMOYO.
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#ifndef _SECURITY_TOMOYO_COMMON_H
+#define _SECURITY_TOMOYO_COMMON_H
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/kmod.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/list.h>
+#include <linux/cred.h>
+#include <linux/poll.h>
+#include <linux/binfmts.h>
+#include <linux/highmem.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/un.h>
+#include <net/sock.h>
+#include <net/af_unix.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
+
+/********** Constants definitions. **********/
+
+/*
+ * TOMOYO uses this hash only when appending a string into the string
+ * table. Frequency of appending strings is very low. So we don't need
+ * large (e.g. 64k) hash size. 256 will be sufficient.
+ */
+#define TOMOYO_HASH_BITS  8
+#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
+
+/*
+ * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
+ * Therefore, we don't need SOCK_MAX.
+ */
+#define TOMOYO_SOCK_MAX 6
+
+#define TOMOYO_EXEC_TMPSIZE     4096
+
+/* Garbage collector is trying to kfree() this element. */
+#define TOMOYO_GC_IN_PROGRESS -1
+
+/* Profile number is an integer between 0 and 255. */
+#define TOMOYO_MAX_PROFILES 256
+
+/* Group number is an integer between 0 and 255. */
+#define TOMOYO_MAX_ACL_GROUPS 256
+
+/* Index numbers for "struct tomoyo_condition". */
+enum tomoyo_conditions_index {
+	TOMOYO_TASK_UID,             /* current_uid()   */
+	TOMOYO_TASK_EUID,            /* current_euid()  */
+	TOMOYO_TASK_SUID,            /* current_suid()  */
+	TOMOYO_TASK_FSUID,           /* current_fsuid() */
+	TOMOYO_TASK_GID,             /* current_gid()   */
+	TOMOYO_TASK_EGID,            /* current_egid()  */
+	TOMOYO_TASK_SGID,            /* current_sgid()  */
+	TOMOYO_TASK_FSGID,           /* current_fsgid() */
+	TOMOYO_TASK_PID,             /* sys_getpid()   */
+	TOMOYO_TASK_PPID,            /* sys_getppid()  */
+	TOMOYO_EXEC_ARGC,            /* "struct linux_binprm *"->argc */
+	TOMOYO_EXEC_ENVC,            /* "struct linux_binprm *"->envc */
+	TOMOYO_TYPE_IS_SOCKET,       /* S_IFSOCK */
+	TOMOYO_TYPE_IS_SYMLINK,      /* S_IFLNK */
+	TOMOYO_TYPE_IS_FILE,         /* S_IFREG */
+	TOMOYO_TYPE_IS_BLOCK_DEV,    /* S_IFBLK */
+	TOMOYO_TYPE_IS_DIRECTORY,    /* S_IFDIR */
+	TOMOYO_TYPE_IS_CHAR_DEV,     /* S_IFCHR */
+	TOMOYO_TYPE_IS_FIFO,         /* S_IFIFO */
+	TOMOYO_MODE_SETUID,          /* S_ISUID */
+	TOMOYO_MODE_SETGID,          /* S_ISGID */
+	TOMOYO_MODE_STICKY,          /* S_ISVTX */
+	TOMOYO_MODE_OWNER_READ,      /* S_IRUSR */
+	TOMOYO_MODE_OWNER_WRITE,     /* S_IWUSR */
+	TOMOYO_MODE_OWNER_EXECUTE,   /* S_IXUSR */
+	TOMOYO_MODE_GROUP_READ,      /* S_IRGRP */
+	TOMOYO_MODE_GROUP_WRITE,     /* S_IWGRP */
+	TOMOYO_MODE_GROUP_EXECUTE,   /* S_IXGRP */
+	TOMOYO_MODE_OTHERS_READ,     /* S_IROTH */
+	TOMOYO_MODE_OTHERS_WRITE,    /* S_IWOTH */
+	TOMOYO_MODE_OTHERS_EXECUTE,  /* S_IXOTH */
+	TOMOYO_EXEC_REALPATH,
+	TOMOYO_SYMLINK_TARGET,
+	TOMOYO_PATH1_UID,
+	TOMOYO_PATH1_GID,
+	TOMOYO_PATH1_INO,
+	TOMOYO_PATH1_MAJOR,
+	TOMOYO_PATH1_MINOR,
+	TOMOYO_PATH1_PERM,
+	TOMOYO_PATH1_TYPE,
+	TOMOYO_PATH1_DEV_MAJOR,
+	TOMOYO_PATH1_DEV_MINOR,
+	TOMOYO_PATH2_UID,
+	TOMOYO_PATH2_GID,
+	TOMOYO_PATH2_INO,
+	TOMOYO_PATH2_MAJOR,
+	TOMOYO_PATH2_MINOR,
+	TOMOYO_PATH2_PERM,
+	TOMOYO_PATH2_TYPE,
+	TOMOYO_PATH2_DEV_MAJOR,
+	TOMOYO_PATH2_DEV_MINOR,
+	TOMOYO_PATH1_PARENT_UID,
+	TOMOYO_PATH1_PARENT_GID,
+	TOMOYO_PATH1_PARENT_INO,
+	TOMOYO_PATH1_PARENT_PERM,
+	TOMOYO_PATH2_PARENT_UID,
+	TOMOYO_PATH2_PARENT_GID,
+	TOMOYO_PATH2_PARENT_INO,
+	TOMOYO_PATH2_PARENT_PERM,
+	TOMOYO_MAX_CONDITION_KEYWORD,
+	TOMOYO_NUMBER_UNION,
+	TOMOYO_NAME_UNION,
+	TOMOYO_ARGV_ENTRY,
+	TOMOYO_ENVP_ENTRY,
+};
+
+
+/* Index numbers for stat(). */
+enum tomoyo_path_stat_index {
+	/* Do not change this order. */
+	TOMOYO_PATH1,
+	TOMOYO_PATH1_PARENT,
+	TOMOYO_PATH2,
+	TOMOYO_PATH2_PARENT,
+	TOMOYO_MAX_PATH_STAT
+};
+
+/* Index numbers for operation mode. */
+enum tomoyo_mode_index {
+	TOMOYO_CONFIG_DISABLED,
+	TOMOYO_CONFIG_LEARNING,
+	TOMOYO_CONFIG_PERMISSIVE,
+	TOMOYO_CONFIG_ENFORCING,
+	TOMOYO_CONFIG_MAX_MODE,
+	TOMOYO_CONFIG_WANT_REJECT_LOG =  64,
+	TOMOYO_CONFIG_WANT_GRANT_LOG  = 128,
+	TOMOYO_CONFIG_USE_DEFAULT     = 255,
+};
+
+/* Index numbers for entry type. */
+enum tomoyo_policy_id {
+	TOMOYO_ID_GROUP,
+	TOMOYO_ID_ADDRESS_GROUP,
+	TOMOYO_ID_PATH_GROUP,
+	TOMOYO_ID_NUMBER_GROUP,
+	TOMOYO_ID_TRANSITION_CONTROL,
+	TOMOYO_ID_AGGREGATOR,
+	TOMOYO_ID_MANAGER,
+	TOMOYO_ID_CONDITION,
+	TOMOYO_ID_NAME,
+	TOMOYO_ID_ACL,
+	TOMOYO_ID_DOMAIN,
+	TOMOYO_MAX_POLICY
+};
+
+/* Index numbers for domain's attributes. */
+enum tomoyo_domain_info_flags_index {
+	/* Quota warnning flag.   */
+	TOMOYO_DIF_QUOTA_WARNED,
+	/*
+	 * This domain was unable to create a new domain at
+	 * tomoyo_find_next_domain() because the name of the domain to be
+	 * created was too long or it could not allocate memory.
+	 * More than one process continued execve() without domain transition.
+	 */
+	TOMOYO_DIF_TRANSITION_FAILED,
+	TOMOYO_MAX_DOMAIN_INFO_FLAGS
+};
+
+/* Index numbers for audit type. */
+enum tomoyo_grant_log {
+	/* Follow profile's configuration. */
+	TOMOYO_GRANTLOG_AUTO,
+	/* Do not generate grant log. */
+	TOMOYO_GRANTLOG_NO,
+	/* Generate grant_log. */
+	TOMOYO_GRANTLOG_YES,
+};
+
+/* Index numbers for group entries. */
+enum tomoyo_group_id {
+	TOMOYO_PATH_GROUP,
+	TOMOYO_NUMBER_GROUP,
+	TOMOYO_ADDRESS_GROUP,
+	TOMOYO_MAX_GROUP
+};
+
+/* Index numbers for type of numeric values. */
+enum tomoyo_value_type {
+	TOMOYO_VALUE_TYPE_INVALID,
+	TOMOYO_VALUE_TYPE_DECIMAL,
+	TOMOYO_VALUE_TYPE_OCTAL,
+	TOMOYO_VALUE_TYPE_HEXADECIMAL,
+};
+
+/* Index numbers for domain transition control keywords. */
+enum tomoyo_transition_type {
+	/* Do not change this order, */
+	TOMOYO_TRANSITION_CONTROL_NO_RESET,
+	TOMOYO_TRANSITION_CONTROL_RESET,
+	TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
+	TOMOYO_TRANSITION_CONTROL_INITIALIZE,
+	TOMOYO_TRANSITION_CONTROL_NO_KEEP,
+	TOMOYO_TRANSITION_CONTROL_KEEP,
+	TOMOYO_MAX_TRANSITION_TYPE
+};
+
+/* Index numbers for Access Controls. */
+enum tomoyo_acl_entry_type_index {
+	TOMOYO_TYPE_PATH_ACL,
+	TOMOYO_TYPE_PATH2_ACL,
+	TOMOYO_TYPE_PATH_NUMBER_ACL,
+	TOMOYO_TYPE_MKDEV_ACL,
+	TOMOYO_TYPE_MOUNT_ACL,
+	TOMOYO_TYPE_INET_ACL,
+	TOMOYO_TYPE_UNIX_ACL,
+	TOMOYO_TYPE_ENV_ACL,
+	TOMOYO_TYPE_MANUAL_TASK_ACL,
+};
+
+/* Index numbers for access controls with one pathname. */
+enum tomoyo_path_acl_index {
+	TOMOYO_TYPE_EXECUTE,
+	TOMOYO_TYPE_READ,
+	TOMOYO_TYPE_WRITE,
+	TOMOYO_TYPE_APPEND,
+	TOMOYO_TYPE_UNLINK,
+	TOMOYO_TYPE_GETATTR,
+	TOMOYO_TYPE_RMDIR,
+	TOMOYO_TYPE_TRUNCATE,
+	TOMOYO_TYPE_SYMLINK,
+	TOMOYO_TYPE_CHROOT,
+	TOMOYO_TYPE_UMOUNT,
+	TOMOYO_MAX_PATH_OPERATION
+};
+
+/* Index numbers for /sys/kernel/security/tomoyo/stat interface. */
+enum tomoyo_memory_stat_type {
+	TOMOYO_MEMORY_POLICY,
+	TOMOYO_MEMORY_AUDIT,
+	TOMOYO_MEMORY_QUERY,
+	TOMOYO_MAX_MEMORY_STAT
+};
+
+enum tomoyo_mkdev_acl_index {
+	TOMOYO_TYPE_MKBLOCK,
+	TOMOYO_TYPE_MKCHAR,
+	TOMOYO_MAX_MKDEV_OPERATION
+};
+
+/* Index numbers for socket operations. */
+enum tomoyo_network_acl_index {
+	TOMOYO_NETWORK_BIND,    /* bind() operation. */
+	TOMOYO_NETWORK_LISTEN,  /* listen() operation. */
+	TOMOYO_NETWORK_CONNECT, /* connect() operation. */
+	TOMOYO_NETWORK_SEND,    /* send() operation. */
+	TOMOYO_MAX_NETWORK_OPERATION
+};
+
+/* Index numbers for access controls with two pathnames. */
+enum tomoyo_path2_acl_index {
+	TOMOYO_TYPE_LINK,
+	TOMOYO_TYPE_RENAME,
+	TOMOYO_TYPE_PIVOT_ROOT,
+	TOMOYO_MAX_PATH2_OPERATION
+};
+
+/* Index numbers for access controls with one pathname and one number. */
+enum tomoyo_path_number_acl_index {
+	TOMOYO_TYPE_CREATE,
+	TOMOYO_TYPE_MKDIR,
+	TOMOYO_TYPE_MKFIFO,
+	TOMOYO_TYPE_MKSOCK,
+	TOMOYO_TYPE_IOCTL,
+	TOMOYO_TYPE_CHMOD,
+	TOMOYO_TYPE_CHOWN,
+	TOMOYO_TYPE_CHGRP,
+	TOMOYO_MAX_PATH_NUMBER_OPERATION
+};
+
+/* Index numbers for /sys/kernel/security/tomoyo/ interfaces. */
+enum tomoyo_securityfs_interface_index {
+	TOMOYO_DOMAINPOLICY,
+	TOMOYO_EXCEPTIONPOLICY,
+	TOMOYO_PROCESS_STATUS,
+	TOMOYO_STAT,
+	TOMOYO_AUDIT,
+	TOMOYO_VERSION,
+	TOMOYO_PROFILE,
+	TOMOYO_QUERY,
+	TOMOYO_MANAGER
+};
+
+/* Index numbers for special mount operations. */
+enum tomoyo_special_mount {
+	TOMOYO_MOUNT_BIND,            /* mount --bind /source /dest   */
+	TOMOYO_MOUNT_MOVE,            /* mount --move /old /new       */
+	TOMOYO_MOUNT_REMOUNT,         /* mount -o remount /dir        */
+	TOMOYO_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
+	TOMOYO_MOUNT_MAKE_PRIVATE,    /* mount --make-private /dir    */
+	TOMOYO_MOUNT_MAKE_SLAVE,      /* mount --make-slave /dir      */
+	TOMOYO_MOUNT_MAKE_SHARED,     /* mount --make-shared /dir     */
+	TOMOYO_MAX_SPECIAL_MOUNT
+};
+
+/* Index numbers for functionality. */
+enum tomoyo_mac_index {
+	TOMOYO_MAC_FILE_EXECUTE,
+	TOMOYO_MAC_FILE_OPEN,
+	TOMOYO_MAC_FILE_CREATE,
+	TOMOYO_MAC_FILE_UNLINK,
+	TOMOYO_MAC_FILE_GETATTR,
+	TOMOYO_MAC_FILE_MKDIR,
+	TOMOYO_MAC_FILE_RMDIR,
+	TOMOYO_MAC_FILE_MKFIFO,
+	TOMOYO_MAC_FILE_MKSOCK,
+	TOMOYO_MAC_FILE_TRUNCATE,
+	TOMOYO_MAC_FILE_SYMLINK,
+	TOMOYO_MAC_FILE_MKBLOCK,
+	TOMOYO_MAC_FILE_MKCHAR,
+	TOMOYO_MAC_FILE_LINK,
+	TOMOYO_MAC_FILE_RENAME,
+	TOMOYO_MAC_FILE_CHMOD,
+	TOMOYO_MAC_FILE_CHOWN,
+	TOMOYO_MAC_FILE_CHGRP,
+	TOMOYO_MAC_FILE_IOCTL,
+	TOMOYO_MAC_FILE_CHROOT,
+	TOMOYO_MAC_FILE_MOUNT,
+	TOMOYO_MAC_FILE_UMOUNT,
+	TOMOYO_MAC_FILE_PIVOT_ROOT,
+	TOMOYO_MAC_NETWORK_INET_STREAM_BIND,
+	TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN,
+	TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT,
+	TOMOYO_MAC_NETWORK_INET_DGRAM_BIND,
+	TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
+	TOMOYO_MAC_NETWORK_INET_RAW_BIND,
+	TOMOYO_MAC_NETWORK_INET_RAW_SEND,
+	TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
+	TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
+	TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
+	TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND,
+	TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND,
+	TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND,
+	TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
+	TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
+	TOMOYO_MAC_ENVIRON,
+	TOMOYO_MAX_MAC_INDEX
+};
+
+/* Index numbers for category of functionality. */
+enum tomoyo_mac_category_index {
+	TOMOYO_MAC_CATEGORY_FILE,
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	TOMOYO_MAC_CATEGORY_MISC,
+	TOMOYO_MAX_MAC_CATEGORY_INDEX
+};
+
+/*
+ * Retry this request. Returned by tomoyo_supervisor() if policy violation has
+ * occurred in enforcing mode and the userspace daemon decided to retry.
+ *
+ * We must choose a positive value in order to distinguish "granted" (which is
+ * 0) and "rejected" (which is a negative value) and "retry".
+ */
+#define TOMOYO_RETRY_REQUEST 1
+
+/* Index numbers for /sys/kernel/security/tomoyo/stat interface. */
+enum tomoyo_policy_stat_type {
+	/* Do not change this order. */
+	TOMOYO_STAT_POLICY_UPDATES,
+	TOMOYO_STAT_POLICY_LEARNING,   /* == TOMOYO_CONFIG_LEARNING */
+	TOMOYO_STAT_POLICY_PERMISSIVE, /* == TOMOYO_CONFIG_PERMISSIVE */
+	TOMOYO_STAT_POLICY_ENFORCING,  /* == TOMOYO_CONFIG_ENFORCING */
+	TOMOYO_MAX_POLICY_STAT
+};
+
+/* Index numbers for profile's PREFERENCE values. */
+enum tomoyo_pref_index {
+	TOMOYO_PREF_MAX_AUDIT_LOG,
+	TOMOYO_PREF_MAX_LEARNING_ENTRY,
+	TOMOYO_MAX_PREF
+};
+
+/********** Structure definitions. **********/
+
+/* Common header for holding ACL entries. */
+struct tomoyo_acl_head {
+	struct list_head list;
+	s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */
+} __packed;
+
+/* Common header for shared entries. */
+struct tomoyo_shared_acl_head {
+	struct list_head list;
+	atomic_t users;
+} __packed;
+
+struct tomoyo_policy_namespace;
+
+/* Structure for request info. */
+struct tomoyo_request_info {
+	/*
+	 * For holding parameters specific to operations which deal files.
+	 * NULL if not dealing files.
+	 */
+	struct tomoyo_obj_info *obj;
+	/*
+	 * For holding parameters specific to execve() request.
+	 * NULL if not dealing do_execve().
+	 */
+	struct tomoyo_execve *ee;
+	struct tomoyo_domain_info *domain;
+	/* For holding parameters. */
+	union {
+		struct {
+			const struct tomoyo_path_info *filename;
+			/* For using wildcards at tomoyo_find_next_domain(). */
+			const struct tomoyo_path_info *matched_path;
+			/* One of values in "enum tomoyo_path_acl_index". */
+			u8 operation;
+		} path;
+		struct {
+			const struct tomoyo_path_info *filename1;
+			const struct tomoyo_path_info *filename2;
+			/* One of values in "enum tomoyo_path2_acl_index". */
+			u8 operation;
+		} path2;
+		struct {
+			const struct tomoyo_path_info *filename;
+			unsigned int mode;
+			unsigned int major;
+			unsigned int minor;
+			/* One of values in "enum tomoyo_mkdev_acl_index". */
+			u8 operation;
+		} mkdev;
+		struct {
+			const struct tomoyo_path_info *filename;
+			unsigned long number;
+			/*
+			 * One of values in
+			 * "enum tomoyo_path_number_acl_index".
+			 */
+			u8 operation;
+		} path_number;
+		struct {
+			const struct tomoyo_path_info *name;
+		} environ;
+		struct {
+			const __be32 *address;
+			u16 port;
+			/* One of values smaller than TOMOYO_SOCK_MAX. */
+			u8 protocol;
+			/* One of values in "enum tomoyo_network_acl_index". */
+			u8 operation;
+			bool is_ipv6;
+		} inet_network;
+		struct {
+			const struct tomoyo_path_info *address;
+			/* One of values smaller than TOMOYO_SOCK_MAX. */
+			u8 protocol;
+			/* One of values in "enum tomoyo_network_acl_index". */
+			u8 operation;
+		} unix_network;
+		struct {
+			const struct tomoyo_path_info *type;
+			const struct tomoyo_path_info *dir;
+			const struct tomoyo_path_info *dev;
+			unsigned long flags;
+			int need_dev;
+		} mount;
+		struct {
+			const struct tomoyo_path_info *domainname;
+		} task;
+	} param;
+	struct tomoyo_acl_info *matched_acl;
+	u8 param_type;
+	bool granted;
+	u8 retry;
+	u8 profile;
+	u8 mode; /* One of tomoyo_mode_index . */
+	u8 type;
+};
+
+/* Structure for holding a token. */
+struct tomoyo_path_info {
+	const char *name;
+	u32 hash;          /* = full_name_hash(name, strlen(name)) */
+	u16 const_len;     /* = tomoyo_const_part_length(name)     */
+	bool is_dir;       /* = tomoyo_strendswith(name, "/")      */
+	bool is_patterned; /* = tomoyo_path_contains_pattern(name) */
+};
+
+/* Structure for holding string data. */
+struct tomoyo_name {
+	struct tomoyo_shared_acl_head head;
+	struct tomoyo_path_info entry;
+};
+
+/* Structure for holding a word. */
+struct tomoyo_name_union {
+	/* Either @filename or @group is NULL. */
+	const struct tomoyo_path_info *filename;
+	struct tomoyo_group *group;
+};
+
+/* Structure for holding a number. */
+struct tomoyo_number_union {
+	unsigned long values[2];
+	struct tomoyo_group *group; /* Maybe NULL. */
+	/* One of values in "enum tomoyo_value_type". */
+	u8 value_type[2];
+};
+
+/* Structure for holding an IP address. */
+struct tomoyo_ipaddr_union {
+	struct in6_addr ip[2]; /* Big endian. */
+	struct tomoyo_group *group; /* Pointer to address group. */
+	bool is_ipv6; /* Valid only if @group == NULL. */
+};
+
+/* Structure for "path_group"/"number_group"/"address_group" directive. */
+struct tomoyo_group {
+	struct tomoyo_shared_acl_head head;
+	const struct tomoyo_path_info *group_name;
+	struct list_head member_list;
+};
+
+/* Structure for "path_group" directive. */
+struct tomoyo_path_group {
+	struct tomoyo_acl_head head;
+	const struct tomoyo_path_info *member_name;
+};
+
+/* Structure for "number_group" directive. */
+struct tomoyo_number_group {
+	struct tomoyo_acl_head head;
+	struct tomoyo_number_union number;
+};
+
+/* Structure for "address_group" directive. */
+struct tomoyo_address_group {
+	struct tomoyo_acl_head head;
+	/* Structure for holding an IP address. */
+	struct tomoyo_ipaddr_union address;
+};
+
+/* Subset of "struct stat". Used by conditional ACL and audit logs. */
+struct tomoyo_mini_stat {
+	uid_t uid;
+	gid_t gid;
+	ino_t ino;
+	umode_t mode;
+	dev_t dev;
+	dev_t rdev;
+};
+
+/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
+struct tomoyo_page_dump {
+	struct page *page;    /* Previously dumped page. */
+	char *data;           /* Contents of "page". Size is PAGE_SIZE. */
+};
+
+/* Structure for attribute checks in addition to pathname checks. */
+struct tomoyo_obj_info {
+	/*
+	 * True if tomoyo_get_attributes() was already called, false otherwise.
+	 */
+	bool validate_done;
+	/* True if @stat[] is valid. */
+	bool stat_valid[TOMOYO_MAX_PATH_STAT];
+	/* First pathname. Initialized with { NULL, NULL } if no path. */
+	struct path path1;
+	/* Second pathname. Initialized with { NULL, NULL } if no path. */
+	struct path path2;
+	/*
+	 * Information on @path1, @path1's parent directory, @path2, @path2's
+	 * parent directory.
+	 */
+	struct tomoyo_mini_stat stat[TOMOYO_MAX_PATH_STAT];
+	/*
+	 * Content of symbolic link to be created. NULL for operations other
+	 * than symlink().
+	 */
+	struct tomoyo_path_info *symlink_target;
+};
+
+/* Structure for argv[]. */
+struct tomoyo_argv {
+	unsigned long index;
+	const struct tomoyo_path_info *value;
+	bool is_not;
+};
+
+/* Structure for envp[]. */
+struct tomoyo_envp {
+	const struct tomoyo_path_info *name;
+	const struct tomoyo_path_info *value;
+	bool is_not;
+};
+
+/* Structure for execve() operation. */
+struct tomoyo_execve {
+	struct tomoyo_request_info r;
+	struct tomoyo_obj_info obj;
+	struct linux_binprm *bprm;
+	const struct tomoyo_path_info *transition;
+	/* For dumping argv[] and envp[]. */
+	struct tomoyo_page_dump dump;
+	/* For temporary use. */
+	char *tmp; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
+};
+
+/* Structure for entries which follows "struct tomoyo_condition". */
+struct tomoyo_condition_element {
+	/*
+	 * Left hand operand. A "struct tomoyo_argv" for TOMOYO_ARGV_ENTRY, a
+	 * "struct tomoyo_envp" for TOMOYO_ENVP_ENTRY is attached to the tail
+	 * of the array of this struct.
+	 */
+	u8 left;
+	/*
+	 * Right hand operand. A "struct tomoyo_number_union" for
+	 * TOMOYO_NUMBER_UNION, a "struct tomoyo_name_union" for
+	 * TOMOYO_NAME_UNION is attached to the tail of the array of this
+	 * struct.
+	 */
+	u8 right;
+	/* Equation operator. True if equals or overlaps, false otherwise. */
+	bool equals;
+};
+
+/* Structure for optional arguments. */
+struct tomoyo_condition {
+	struct tomoyo_shared_acl_head head;
+	u32 size; /* Memory size allocated for this entry. */
+	u16 condc; /* Number of conditions in this struct. */
+	u16 numbers_count; /* Number of "struct tomoyo_number_union values". */
+	u16 names_count; /* Number of "struct tomoyo_name_union names". */
+	u16 argc; /* Number of "struct tomoyo_argv". */
+	u16 envc; /* Number of "struct tomoyo_envp". */
+	u8 grant_log; /* One of values in "enum tomoyo_grant_log". */
+	const struct tomoyo_path_info *transit; /* Maybe NULL. */
+	/*
+	 * struct tomoyo_condition_element condition[condc];
+	 * struct tomoyo_number_union values[numbers_count];
+	 * struct tomoyo_name_union names[names_count];
+	 * struct tomoyo_argv argv[argc];
+	 * struct tomoyo_envp envp[envc];
+	 */
+};
+
+/* Common header for individual entries. */
+struct tomoyo_acl_info {
+	struct list_head list;
+	struct tomoyo_condition *cond; /* Maybe NULL. */
+	s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */
+	u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */
+} __packed;
+
+/* Structure for domain information. */
+struct tomoyo_domain_info {
+	struct list_head list;
+	struct list_head acl_info_list;
+	/* Name of this domain. Never NULL.          */
+	const struct tomoyo_path_info *domainname;
+	/* Namespace for this domain. Never NULL. */
+	struct tomoyo_policy_namespace *ns;
+	u8 profile;        /* Profile number to use. */
+	u8 group;          /* Group number to use.   */
+	bool is_deleted;   /* Delete flag.           */
+	bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
+	atomic_t users; /* Number of referring credentials. */
+};
+
+/*
+ * Structure for "task manual_domain_transition" directive.
+ */
+struct tomoyo_task_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MANUAL_TASK_ACL */
+	/* Pointer to domainname. */
+	const struct tomoyo_path_info *domainname;
+};
+
+/*
+ * Structure for "file execute", "file read", "file write", "file append",
+ * "file unlink", "file getattr", "file rmdir", "file truncate",
+ * "file symlink", "file chroot" and "file unmount" directive.
+ */
+struct tomoyo_path_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
+	u16 perm; /* Bitmask of values in "enum tomoyo_path_acl_index". */
+	struct tomoyo_name_union name;
+};
+
+/*
+ * Structure for "file create", "file mkdir", "file mkfifo", "file mksock",
+ * "file ioctl", "file chmod", "file chown" and "file chgrp" directive.
+ */
+struct tomoyo_path_number_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */
+	/* Bitmask of values in "enum tomoyo_path_number_acl_index". */
+	u8 perm;
+	struct tomoyo_name_union name;
+	struct tomoyo_number_union number;
+};
+
+/* Structure for "file mkblock" and "file mkchar" directive. */
+struct tomoyo_mkdev_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */
+	u8 perm; /* Bitmask of values in "enum tomoyo_mkdev_acl_index". */
+	struct tomoyo_name_union name;
+	struct tomoyo_number_union mode;
+	struct tomoyo_number_union major;
+	struct tomoyo_number_union minor;
+};
+
+/*
+ * Structure for "file rename", "file link" and "file pivot_root" directive.
+ */
+struct tomoyo_path2_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */
+	u8 perm; /* Bitmask of values in "enum tomoyo_path2_acl_index". */
+	struct tomoyo_name_union name1;
+	struct tomoyo_name_union name2;
+};
+
+/* Structure for "file mount" directive. */
+struct tomoyo_mount_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
+	struct tomoyo_name_union dev_name;
+	struct tomoyo_name_union dir_name;
+	struct tomoyo_name_union fs_type;
+	struct tomoyo_number_union flags;
+};
+
+/* Structure for "misc env" directive in domain policy. */
+struct tomoyo_env_acl {
+	struct tomoyo_acl_info head;        /* type = TOMOYO_TYPE_ENV_ACL  */
+	const struct tomoyo_path_info *env; /* environment variable */
+};
+
+/* Structure for "network inet" directive. */
+struct tomoyo_inet_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_INET_ACL */
+	u8 protocol;
+	u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */
+	struct tomoyo_ipaddr_union address;
+	struct tomoyo_number_union port;
+};
+
+/* Structure for "network unix" directive. */
+struct tomoyo_unix_acl {
+	struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_UNIX_ACL */
+	u8 protocol;
+	u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */
+	struct tomoyo_name_union name;
+};
+
+/* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */
+struct tomoyo_acl_param {
+	char *data;
+	struct list_head *list;
+	struct tomoyo_policy_namespace *ns;
+	bool is_delete;
+};
+
+#define TOMOYO_MAX_IO_READ_QUEUE 64
+
+/*
+ * Structure for reading/writing policy via /sys/kernel/security/tomoyo
+ * interfaces.
+ */
+struct tomoyo_io_buffer {
+	void (*read) (struct tomoyo_io_buffer *);
+	int (*write) (struct tomoyo_io_buffer *);
+	unsigned int (*poll) (struct file *file, poll_table *wait);
+	/* Exclusive lock for this structure.   */
+	struct mutex io_sem;
+	char __user *read_user_buf;
+	size_t read_user_buf_avail;
+	struct {
+		struct list_head *ns;
+		struct list_head *domain;
+		struct list_head *group;
+		struct list_head *acl;
+		size_t avail;
+		unsigned int step;
+		unsigned int query_index;
+		u16 index;
+		u16 cond_index;
+		u8 acl_group_index;
+		u8 cond_step;
+		u8 bit;
+		u8 w_pos;
+		bool eof;
+		bool print_this_domain_only;
+		bool print_transition_related_only;
+		bool print_cond_part;
+		const char *w[TOMOYO_MAX_IO_READ_QUEUE];
+	} r;
+	struct {
+		struct tomoyo_policy_namespace *ns;
+		/* The position currently writing to.   */
+		struct tomoyo_domain_info *domain;
+		/* Bytes available for writing.         */
+		size_t avail;
+		bool is_delete;
+	} w;
+	/* Buffer for reading.                  */
+	char *read_buf;
+	/* Size of read buffer.                 */
+	size_t readbuf_size;
+	/* Buffer for writing.                  */
+	char *write_buf;
+	/* Size of write buffer.                */
+	size_t writebuf_size;
+	/* Type of this interface.              */
+	enum tomoyo_securityfs_interface_index type;
+	/* Users counter protected by tomoyo_io_buffer_list_lock. */
+	u8 users;
+	/* List for telling GC not to kfree() elements. */
+	struct list_head list;
+};
+
+/*
+ * Structure for "initialize_domain"/"no_initialize_domain"/"keep_domain"/
+ * "no_keep_domain" keyword.
+ */
+struct tomoyo_transition_control {
+	struct tomoyo_acl_head head;
+	u8 type; /* One of values in "enum tomoyo_transition_type".  */
+	/* True if the domainname is tomoyo_get_last_name(). */
+	bool is_last_name;
+	const struct tomoyo_path_info *domainname; /* Maybe NULL */
+	const struct tomoyo_path_info *program;    /* Maybe NULL */
+};
+
+/* Structure for "aggregator" keyword. */
+struct tomoyo_aggregator {
+	struct tomoyo_acl_head head;
+	const struct tomoyo_path_info *original_name;
+	const struct tomoyo_path_info *aggregated_name;
+};
+
+/* Structure for policy manager. */
+struct tomoyo_manager {
+	struct tomoyo_acl_head head;
+	bool is_domain;  /* True if manager is a domainname. */
+	/* A path to program or a domainname. */
+	const struct tomoyo_path_info *manager;
+};
+
+struct tomoyo_preference {
+	unsigned int learning_max_entry;
+	bool enforcing_verbose;
+	bool learning_verbose;
+	bool permissive_verbose;
+};
+
+/* Structure for /sys/kernel/security/tomnoyo/profile interface. */
+struct tomoyo_profile {
+	const struct tomoyo_path_info *comment;
+	struct tomoyo_preference *learning;
+	struct tomoyo_preference *permissive;
+	struct tomoyo_preference *enforcing;
+	struct tomoyo_preference preference;
+	u8 default_config;
+	u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+	unsigned int pref[TOMOYO_MAX_PREF];
+};
+
+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
+struct tomoyo_time {
+	u16 year;
+	u8 month;
+	u8 day;
+	u8 hour;
+	u8 min;
+	u8 sec;
+};
+
+/* Structure for policy namespace. */
+struct tomoyo_policy_namespace {
+	/* Profile table. Memory is allocated as needed. */
+	struct tomoyo_profile *profile_ptr[TOMOYO_MAX_PROFILES];
+	/* List of "struct tomoyo_group". */
+	struct list_head group_list[TOMOYO_MAX_GROUP];
+	/* List of policy. */
+	struct list_head policy_list[TOMOYO_MAX_POLICY];
+	/* The global ACL referred by "use_group" keyword. */
+	struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
+	/* List for connecting to tomoyo_namespace_list list. */
+	struct list_head namespace_list;
+	/* Profile version. Currently only 20110903 is defined. */
+	unsigned int profile_version;
+	/* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
+	const char *name;
+};
+
+/********** Function prototypes. **********/
+
+bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
+				  const struct tomoyo_group *group);
+bool tomoyo_compare_number_union(const unsigned long value,
+				 const struct tomoyo_number_union *ptr);
+bool tomoyo_condition(struct tomoyo_request_info *r,
+		      const struct tomoyo_condition *cond);
+bool tomoyo_correct_domain(const unsigned char *domainname);
+bool tomoyo_correct_path(const char *filename);
+bool tomoyo_correct_word(const char *string);
+bool tomoyo_domain_def(const unsigned char *buffer);
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
+bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
+		      struct tomoyo_page_dump *dump);
+bool tomoyo_memory_ok(void *ptr);
+bool tomoyo_number_matches_group(const unsigned long min,
+				 const unsigned long max,
+				 const struct tomoyo_group *group);
+bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param,
+			       struct tomoyo_ipaddr_union *ptr);
+bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
+			     struct tomoyo_name_union *ptr);
+bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
+			       struct tomoyo_number_union *ptr);
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+				 const struct tomoyo_path_info *pattern);
+bool tomoyo_permstr(const char *string, const char *keyword);
+bool tomoyo_str_starts(char **src, const char *find);
+char *tomoyo_encode(const char *str);
+char *tomoyo_encode2(const char *str, int str_len);
+char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
+		      va_list args);
+char *tomoyo_read_token(struct tomoyo_acl_param *param);
+char *tomoyo_realpath_from_path(struct path *path);
+char *tomoyo_realpath_nofollow(const char *pathname);
+const char *tomoyo_get_exe(void);
+const char *tomoyo_yesno(const unsigned int value);
+const struct tomoyo_path_info *tomoyo_compare_name_union
+(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr);
+const struct tomoyo_path_info *tomoyo_get_domainname
+(struct tomoyo_acl_param *param);
+const struct tomoyo_path_info *tomoyo_get_name(const char *name);
+const struct tomoyo_path_info *tomoyo_path_matches_group
+(const struct tomoyo_path_info *pathname, const struct tomoyo_group *group);
+int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
+				 struct path *path, const int flag);
+int tomoyo_close_control(struct tomoyo_io_buffer *head);
+int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env);
+int tomoyo_execute_permission(struct tomoyo_request_info *r,
+			      const struct tomoyo_path_info *filename);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);
+int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
+		    const u8 index);
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+			     struct tomoyo_domain_info *domain,
+			     const u8 index);
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+		      const unsigned int mode, unsigned int dev);
+int tomoyo_mount_permission(char *dev_name, struct path *path,
+			    const char *type, unsigned long flags,
+			    void *data_page);
+int tomoyo_open_control(const u8 type, struct file *file);
+int tomoyo_path2_perm(const u8 operation, struct path *path1,
+		      struct path *path2);
+int tomoyo_path_number_perm(const u8 operation, struct path *path,
+			    unsigned long number);
+int tomoyo_path_perm(const u8 operation, struct path *path,
+		     const char *target);
+unsigned int tomoyo_poll_control(struct file *file, poll_table *wait);
+unsigned int tomoyo_poll_log(struct file *file, poll_table *wait);
+int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
+				  int addr_len);
+int tomoyo_socket_connect_permission(struct socket *sock,
+				     struct sockaddr *addr, int addr_len);
+int tomoyo_socket_listen_permission(struct socket *sock);
+int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
+				     int size);
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+	__printf(2, 3);
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+			 struct tomoyo_acl_param *param,
+			 bool (*check_duplicate)
+			 (const struct tomoyo_acl_info *,
+			  const struct tomoyo_acl_info *),
+			 bool (*merge_duplicate)
+			 (struct tomoyo_acl_info *, struct tomoyo_acl_info *,
+			  const bool));
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+			 struct tomoyo_acl_param *param,
+			 bool (*check_duplicate)
+			 (const struct tomoyo_acl_head *,
+			  const struct tomoyo_acl_head *));
+int tomoyo_write_aggregator(struct tomoyo_acl_param *param);
+int tomoyo_write_file(struct tomoyo_acl_param *param);
+int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type);
+int tomoyo_write_misc(struct tomoyo_acl_param *param);
+int tomoyo_write_inet_network(struct tomoyo_acl_param *param);
+int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
+				    const u8 type);
+int tomoyo_write_unix_network(struct tomoyo_acl_param *param);
+ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
+			    const int buffer_len);
+ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
+			     const char __user *buffer, const int buffer_len);
+struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param);
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+						const bool transit);
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
+struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
+				      const u8 idx);
+struct tomoyo_policy_namespace *tomoyo_assign_namespace
+(const char *domainname);
+struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
+				      const u8 profile);
+unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
+				const u8 index);
+u8 tomoyo_parse_ulong(unsigned long *result, char **str);
+void *tomoyo_commit_ok(void *data, const unsigned int size);
+void __init tomoyo_load_builtin_policy(void);
+void __init tomoyo_mm_init(void);
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+		      bool (*check_entry) (struct tomoyo_request_info *,
+					   const struct tomoyo_acl_info *));
+void tomoyo_check_profile(void);
+void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp);
+void tomoyo_del_condition(struct list_head *element);
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
+void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
+void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
+void tomoyo_load_policy(const char *filename);
+void tomoyo_normalize_line(unsigned char *buffer);
+void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register);
+void tomoyo_print_ip(char *buf, const unsigned int size,
+		     const struct tomoyo_ipaddr_union *ptr);
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+			const unsigned long value, const u8 type);
+void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
+void tomoyo_read_log(struct tomoyo_io_buffer *head);
+void tomoyo_update_stat(const u8 index);
+void tomoyo_warn_oom(const char *function);
+void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
+	__printf(2, 3);
+void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
+		       va_list args);
+
+/********** External variable definitions. **********/
+
+extern bool tomoyo_policy_loaded;
+extern const char * const tomoyo_condition_keyword
+[TOMOYO_MAX_CONDITION_KEYWORD];
+extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
+extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+					      + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE];
+extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX];
+extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION];
+extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
+extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
+extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
+extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION];
+extern struct list_head tomoyo_condition_list;
+extern struct list_head tomoyo_domain_list;
+extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+extern struct list_head tomoyo_namespace_list;
+extern struct mutex tomoyo_policy_lock;
+extern struct srcu_struct tomoyo_ss;
+extern struct tomoyo_domain_info tomoyo_kernel_domain;
+extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
+extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
+extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+
+/********** Inlined functions. **********/
+
+/**
+ * tomoyo_read_lock - Take lock for protecting policy.
+ *
+ * Returns index number for tomoyo_read_unlock().
+ */
+static inline int tomoyo_read_lock(void)
+{
+	return srcu_read_lock(&tomoyo_ss);
+}
+
+/**
+ * tomoyo_read_unlock - Release lock for protecting policy.
+ *
+ * @idx: Index number returned by tomoyo_read_lock().
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_read_unlock(int idx)
+{
+	srcu_read_unlock(&tomoyo_ss, idx);
+}
+
+/**
+ * tomoyo_sys_getppid - Copy of getppid().
+ *
+ * Returns parent process's PID.
+ *
+ * Alpha does not have getppid() defined. To be able to build this module on
+ * Alpha, I have to copy getppid() from kernel/timer.c.
+ */
+static inline pid_t tomoyo_sys_getppid(void)
+{
+	pid_t pid;
+	rcu_read_lock();
+	pid = task_tgid_vnr(rcu_dereference(current->real_parent));
+	rcu_read_unlock();
+	return pid;
+}
+
+/**
+ * tomoyo_sys_getpid - Copy of getpid().
+ *
+ * Returns current thread's PID.
+ *
+ * Alpha does not have getpid() defined. To be able to build this module on
+ * Alpha, I have to copy getpid() from kernel/timer.c.
+ */
+static inline pid_t tomoyo_sys_getpid(void)
+{
+	return task_tgid_vnr(current);
+}
+
+/**
+ * tomoyo_pathcmp - strcmp() for "struct tomoyo_path_info" structure.
+ *
+ * @a: Pointer to "struct tomoyo_path_info".
+ * @b: Pointer to "struct tomoyo_path_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
+				  const struct tomoyo_path_info *b)
+{
+	return a->hash != b->hash || strcmp(a->name, b->name);
+}
+
+/**
+ * tomoyo_put_name - Drop reference on "struct tomoyo_name".
+ *
+ * @name: Pointer to "struct tomoyo_path_info". Maybe NULL.
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
+{
+	if (name) {
+		struct tomoyo_name *ptr =
+			container_of(name, typeof(*ptr), entry);
+		atomic_dec(&ptr->head.users);
+	}
+}
+
+/**
+ * tomoyo_put_condition - Drop reference on "struct tomoyo_condition".
+ *
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_put_condition(struct tomoyo_condition *cond)
+{
+	if (cond)
+		atomic_dec(&cond->head.users);
+}
+
+/**
+ * tomoyo_put_group - Drop reference on "struct tomoyo_group".
+ *
+ * @group: Pointer to "struct tomoyo_group". Maybe NULL.
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_put_group(struct tomoyo_group *group)
+{
+	if (group)
+		atomic_dec(&group->head.users);
+}
+
+/**
+ * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" for current thread.
+ */
+static inline struct tomoyo_domain_info *tomoyo_domain(void)
+{
+	return current_cred()->security;
+}
+
+/**
+ * tomoyo_real_domain - Get "struct tomoyo_domain_info" for specified thread.
+ *
+ * @task: Pointer to "struct task_struct".
+ *
+ * Returns pointer to "struct tomoyo_security" for specified thread.
+ */
+static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
+							    *task)
+{
+	return task_cred_xxx(task, security);
+}
+
+/**
+ * tomoyo_same_name_union - Check for duplicated "struct tomoyo_name_union" entry.
+ *
+ * @a: Pointer to "struct tomoyo_name_union".
+ * @b: Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_name_union
+(const struct tomoyo_name_union *a, const struct tomoyo_name_union *b)
+{
+	return a->filename == b->filename && a->group == b->group;
+}
+
+/**
+ * tomoyo_same_number_union - Check for duplicated "struct tomoyo_number_union" entry.
+ *
+ * @a: Pointer to "struct tomoyo_number_union".
+ * @b: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_number_union
+(const struct tomoyo_number_union *a, const struct tomoyo_number_union *b)
+{
+	return a->values[0] == b->values[0] && a->values[1] == b->values[1] &&
+		a->group == b->group && a->value_type[0] == b->value_type[0] &&
+		a->value_type[1] == b->value_type[1];
+}
+
+/**
+ * tomoyo_same_ipaddr_union - Check for duplicated "struct tomoyo_ipaddr_union" entry.
+ *
+ * @a: Pointer to "struct tomoyo_ipaddr_union".
+ * @b: Pointer to "struct tomoyo_ipaddr_union".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_ipaddr_union
+(const struct tomoyo_ipaddr_union *a, const struct tomoyo_ipaddr_union *b)
+{
+	return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group &&
+		a->is_ipv6 == b->is_ipv6;
+}
+
+/**
+ * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread.
+ *
+ * Returns pointer to "struct tomoyo_policy_namespace" for current thread.
+ */
+static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void)
+{
+	return tomoyo_domain()->ns;
+}
+
+#if defined(CONFIG_SLOB)
+
+/**
+ * tomoyo_round2 - Round up to power of 2 for calculating memory usage.
+ *
+ * @size: Size to be rounded up.
+ *
+ * Returns @size.
+ *
+ * Since SLOB does not round up, this function simply returns @size.
+ */
+static inline int tomoyo_round2(size_t size)
+{
+	return size;
+}
+
+#else
+
+/**
+ * tomoyo_round2 - Round up to power of 2 for calculating memory usage.
+ *
+ * @size: Size to be rounded up.
+ *
+ * Returns rounded size.
+ *
+ * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
+ * (e.g.) 128 bytes.
+ */
+static inline int tomoyo_round2(size_t size)
+{
+#if PAGE_SIZE == 4096
+	size_t bsize = 32;
+#else
+	size_t bsize = 64;
+#endif
+	if (!size)
+		return 0;
+	while (size > bsize)
+		bsize <<= 1;
+	return bsize;
+}
+
+#endif
+
+/**
+ * list_for_each_cookie - iterate over a list with cookie.
+ * @pos:        the &struct list_head to use as a loop cursor.
+ * @head:       the head for your list.
+ */
+#define list_for_each_cookie(pos, head)					\
+	if (!pos)							\
+		pos =  srcu_dereference((head)->next, &tomoyo_ss);	\
+	for ( ; pos != (head); pos = srcu_dereference(pos->next, &tomoyo_ss))
+
+#endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/condition.c b/ap/os/linux/linux-3.4.x/security/tomoyo/condition.c
new file mode 100644
index 0000000..986330b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/condition.c
@@ -0,0 +1,1094 @@
+/*
+ * security/tomoyo/condition.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/* List of "struct tomoyo_condition". */
+LIST_HEAD(tomoyo_condition_list);
+
+/**
+ * tomoyo_argv - Check argv[] in "struct linux_binbrm".
+ *
+ * @index:   Index number of @arg_ptr.
+ * @arg_ptr: Contents of argv[@index].
+ * @argc:    Length of @argv.
+ * @argv:    Pointer to "struct tomoyo_argv".
+ * @checked: Set to true if @argv[@index] was found.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
+			const int argc, const struct tomoyo_argv *argv,
+			u8 *checked)
+{
+	int i;
+	struct tomoyo_path_info arg;
+	arg.name = arg_ptr;
+	for (i = 0; i < argc; argv++, checked++, i++) {
+		bool result;
+		if (index != argv->index)
+			continue;
+		*checked = 1;
+		tomoyo_fill_path_info(&arg);
+		result = tomoyo_path_matches_pattern(&arg, argv->value);
+		if (argv->is_not)
+			result = !result;
+		if (!result)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * tomoyo_envp - Check envp[] in "struct linux_binbrm".
+ *
+ * @env_name:  The name of environment variable.
+ * @env_value: The value of environment variable.
+ * @envc:      Length of @envp.
+ * @envp:      Pointer to "struct tomoyo_envp".
+ * @checked:   Set to true if @envp[@env_name] was found.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_envp(const char *env_name, const char *env_value,
+			const int envc, const struct tomoyo_envp *envp,
+			u8 *checked)
+{
+	int i;
+	struct tomoyo_path_info name;
+	struct tomoyo_path_info value;
+	name.name = env_name;
+	tomoyo_fill_path_info(&name);
+	value.name = env_value;
+	tomoyo_fill_path_info(&value);
+	for (i = 0; i < envc; envp++, checked++, i++) {
+		bool result;
+		if (!tomoyo_path_matches_pattern(&name, envp->name))
+			continue;
+		*checked = 1;
+		if (envp->value) {
+			result = tomoyo_path_matches_pattern(&value,
+							     envp->value);
+			if (envp->is_not)
+				result = !result;
+		} else {
+			result = true;
+			if (!envp->is_not)
+				result = !result;
+		}
+		if (!result)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * tomoyo_scan_bprm - Scan "struct linux_binprm".
+ *
+ * @ee:   Pointer to "struct tomoyo_execve".
+ * @argc: Length of @argc.
+ * @argv: Pointer to "struct tomoyo_argv".
+ * @envc: Length of @envp.
+ * @envp: Poiner to "struct tomoyo_envp".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
+			     const u16 argc, const struct tomoyo_argv *argv,
+			     const u16 envc, const struct tomoyo_envp *envp)
+{
+	struct linux_binprm *bprm = ee->bprm;
+	struct tomoyo_page_dump *dump = &ee->dump;
+	char *arg_ptr = ee->tmp;
+	int arg_len = 0;
+	unsigned long pos = bprm->p;
+	int offset = pos % PAGE_SIZE;
+	int argv_count = bprm->argc;
+	int envp_count = bprm->envc;
+	bool result = true;
+	u8 local_checked[32];
+	u8 *checked;
+	if (argc + envc <= sizeof(local_checked)) {
+		checked = local_checked;
+		memset(local_checked, 0, sizeof(local_checked));
+	} else {
+		checked = kzalloc(argc + envc, GFP_NOFS);
+		if (!checked)
+			return false;
+	}
+	while (argv_count || envp_count) {
+		if (!tomoyo_dump_page(bprm, pos, dump)) {
+			result = false;
+			goto out;
+		}
+		pos += PAGE_SIZE - offset;
+		while (offset < PAGE_SIZE) {
+			/* Read. */
+			const char *kaddr = dump->data;
+			const unsigned char c = kaddr[offset++];
+			if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
+				if (c == '\\') {
+					arg_ptr[arg_len++] = '\\';
+					arg_ptr[arg_len++] = '\\';
+				} else if (c > ' ' && c < 127) {
+					arg_ptr[arg_len++] = c;
+				} else {
+					arg_ptr[arg_len++] = '\\';
+					arg_ptr[arg_len++] = (c >> 6) + '0';
+					arg_ptr[arg_len++] =
+						((c >> 3) & 7) + '0';
+					arg_ptr[arg_len++] = (c & 7) + '0';
+				}
+			} else {
+				arg_ptr[arg_len] = '\0';
+			}
+			if (c)
+				continue;
+			/* Check. */
+			if (argv_count) {
+				if (!tomoyo_argv(bprm->argc - argv_count,
+						 arg_ptr, argc, argv,
+						 checked)) {
+					result = false;
+					break;
+				}
+				argv_count--;
+			} else if (envp_count) {
+				char *cp = strchr(arg_ptr, '=');
+				if (cp) {
+					*cp = '\0';
+					if (!tomoyo_envp(arg_ptr, cp + 1,
+							 envc, envp,
+							 checked + argc)) {
+						result = false;
+						break;
+					}
+				}
+				envp_count--;
+			} else {
+				break;
+			}
+			arg_len = 0;
+		}
+		offset = 0;
+		if (!result)
+			break;
+	}
+out:
+	if (result) {
+		int i;
+		/* Check not-yet-checked entries. */
+		for (i = 0; i < argc; i++) {
+			if (checked[i])
+				continue;
+			/*
+			 * Return true only if all unchecked indexes in
+			 * bprm->argv[] are not matched.
+			 */
+			if (argv[i].is_not)
+				continue;
+			result = false;
+			break;
+		}
+		for (i = 0; i < envc; envp++, i++) {
+			if (checked[argc + i])
+				continue;
+			/*
+			 * Return true only if all unchecked environ variables
+			 * in bprm->envp[] are either undefined or not matched.
+			 */
+			if ((!envp->value && !envp->is_not) ||
+			    (envp->value && envp->is_not))
+				continue;
+			result = false;
+			break;
+		}
+	}
+	if (checked != local_checked)
+		kfree(checked);
+	return result;
+}
+
+/**
+ * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
+ *
+ * @file:  Pointer to "struct file".
+ * @ptr:   Pointer to "struct tomoyo_name_union".
+ * @match: True if "exec.realpath=", false if "exec.realpath!=".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_scan_exec_realpath(struct file *file,
+				      const struct tomoyo_name_union *ptr,
+				      const bool match)
+{
+	bool result;
+	struct tomoyo_path_info exe;
+	if (!file)
+		return false;
+	exe.name = tomoyo_realpath_from_path(&file->f_path);
+	if (!exe.name)
+		return false;
+	tomoyo_fill_path_info(&exe);
+	result = tomoyo_compare_name_union(&exe, ptr);
+	kfree(exe.name);
+	return result == match;
+}
+
+/**
+ * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
+ *
+ * @start: String to save.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
+{
+	char *cp = start + strlen(start) - 1;
+	if (cp == start || *start++ != '"' || *cp != '"')
+		return NULL;
+	*cp = '\0';
+	if (*start && !tomoyo_correct_word(start))
+		return NULL;
+	return tomoyo_get_name(start);
+}
+
+/**
+ * tomoyo_parse_name_union_quoted - Parse a quoted word.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
+					   struct tomoyo_name_union *ptr)
+{
+	char *filename = param->data;
+	if (*filename == '@')
+		return tomoyo_parse_name_union(param, ptr);
+	ptr->filename = tomoyo_get_dqword(filename);
+	return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_argv - Parse an argv[] condition part.
+ *
+ * @left:  Lefthand value.
+ * @right: Righthand value.
+ * @argv:  Pointer to "struct tomoyo_argv".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_parse_argv(char *left, char *right,
+			      struct tomoyo_argv *argv)
+{
+	if (tomoyo_parse_ulong(&argv->index, &left) !=
+	    TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
+		return false;
+	argv->value = tomoyo_get_dqword(right);
+	return argv->value != NULL;
+}
+
+/**
+ * tomoyo_parse_envp - Parse an envp[] condition part.
+ *
+ * @left:  Lefthand value.
+ * @right: Righthand value.
+ * @envp:  Pointer to "struct tomoyo_envp".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_parse_envp(char *left, char *right,
+			      struct tomoyo_envp *envp)
+{
+	const struct tomoyo_path_info *name;
+	const struct tomoyo_path_info *value;
+	char *cp = left + strlen(left) - 1;
+	if (*cp-- != ']' || *cp != '"')
+		goto out;
+	*cp = '\0';
+	if (!tomoyo_correct_word(left))
+		goto out;
+	name = tomoyo_get_name(left);
+	if (!name)
+		goto out;
+	if (!strcmp(right, "NULL")) {
+		value = NULL;
+	} else {
+		value = tomoyo_get_dqword(right);
+		if (!value) {
+			tomoyo_put_name(name);
+			goto out;
+		}
+	}
+	envp->name = name;
+	envp->value = value;
+	return true;
+out:
+	return false;
+}
+
+/**
+ * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
+ *
+ * @a: Pointer to "struct tomoyo_condition".
+ * @b: Pointer to "struct tomoyo_condition".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
+					 const struct tomoyo_condition *b)
+{
+	return a->size == b->size && a->condc == b->condc &&
+		a->numbers_count == b->numbers_count &&
+		a->names_count == b->names_count &&
+		a->argc == b->argc && a->envc == b->envc &&
+		a->grant_log == b->grant_log && a->transit == b->transit &&
+		!memcmp(a + 1, b + 1, a->size - sizeof(*a));
+}
+
+/**
+ * tomoyo_condition_type - Get condition type.
+ *
+ * @word: Keyword string.
+ *
+ * Returns one of values in "enum tomoyo_conditions_index" on success,
+ * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
+ */
+static u8 tomoyo_condition_type(const char *word)
+{
+	u8 i;
+	for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
+		if (!strcmp(word, tomoyo_condition_keyword[i]))
+			break;
+	}
+	return i;
+}
+
+/* Define this to enable debug mode. */
+/* #define DEBUG_CONDITION */
+
+#ifdef DEBUG_CONDITION
+#define dprintk printk
+#else
+#define dprintk(...) do { } while (0)
+#endif
+
+/**
+ * tomoyo_commit_condition - Commit "struct tomoyo_condition".
+ *
+ * @entry: Pointer to "struct tomoyo_condition".
+ *
+ * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
+ *
+ * This function merges duplicated entries. This function returns NULL if
+ * @entry is not duplicated but memory quota for policy has exceeded.
+ */
+static struct tomoyo_condition *tomoyo_commit_condition
+(struct tomoyo_condition *entry)
+{
+	struct tomoyo_condition *ptr;
+	bool found = false;
+	if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
+		dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
+		ptr = NULL;
+		found = true;
+		goto out;
+	}
+	list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
+		if (!tomoyo_same_condition(ptr, entry) ||
+		    atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
+			continue;
+		/* Same entry found. Share this entry. */
+		atomic_inc(&ptr->head.users);
+		found = true;
+		break;
+	}
+	if (!found) {
+		if (tomoyo_memory_ok(entry)) {
+			atomic_set(&entry->head.users, 1);
+			list_add(&entry->head.list, &tomoyo_condition_list);
+		} else {
+			found = true;
+			ptr = NULL;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+out:
+	if (found) {
+		tomoyo_del_condition(&entry->head.list);
+		kfree(entry);
+		entry = ptr;
+	}
+	return entry;
+}
+
+/**
+ * tomoyo_get_transit_preference - Parse domain transition preference for execve().
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @e:     Pointer to "struct tomoyo_condition".
+ *
+ * Returns the condition string part.
+ */
+static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
+					   struct tomoyo_condition *e)
+{
+	char * const pos = param->data;
+	bool flag;
+	if (*pos == '<') {
+		e->transit = tomoyo_get_domainname(param);
+		goto done;
+	}
+	{
+		char *cp = strchr(pos, ' ');
+		if (cp)
+			*cp = '\0';
+		flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
+			!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
+			!strcmp(pos, "child") || !strcmp(pos, "parent");
+		if (cp)
+			*cp = ' ';
+	}
+	if (!flag)
+		return pos;
+	e->transit = tomoyo_get_name(tomoyo_read_token(param));
+done:
+	if (e->transit)
+		return param->data;
+	/*
+	 * Return a bad read-only condition string that will let
+	 * tomoyo_get_condition() return NULL.
+	 */
+	return "/";
+}
+
+/**
+ * tomoyo_get_condition - Parse condition part.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
+ */
+struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
+{
+	struct tomoyo_condition *entry = NULL;
+	struct tomoyo_condition_element *condp = NULL;
+	struct tomoyo_number_union *numbers_p = NULL;
+	struct tomoyo_name_union *names_p = NULL;
+	struct tomoyo_argv *argv = NULL;
+	struct tomoyo_envp *envp = NULL;
+	struct tomoyo_condition e = { };
+	char * const start_of_string =
+		tomoyo_get_transit_preference(param, &e);
+	char * const end_of_string = start_of_string + strlen(start_of_string);
+	char *pos;
+rerun:
+	pos = start_of_string;
+	while (1) {
+		u8 left = -1;
+		u8 right = -1;
+		char *left_word = pos;
+		char *cp;
+		char *right_word;
+		bool is_not;
+		if (!*left_word)
+			break;
+		/*
+		 * Since left-hand condition does not allow use of "path_group"
+		 * or "number_group" and environment variable's names do not
+		 * accept '=', it is guaranteed that the original line consists
+		 * of one or more repetition of $left$operator$right blocks
+		 * where "$left is free from '=' and ' '" and "$operator is
+		 * either '=' or '!='" and "$right is free from ' '".
+		 * Therefore, we can reconstruct the original line at the end
+		 * of dry run even if we overwrite $operator with '\0'.
+		 */
+		cp = strchr(pos, ' ');
+		if (cp) {
+			*cp = '\0'; /* Will restore later. */
+			pos = cp + 1;
+		} else {
+			pos = "";
+		}
+		right_word = strchr(left_word, '=');
+		if (!right_word || right_word == left_word)
+			goto out;
+		is_not = *(right_word - 1) == '!';
+		if (is_not)
+			*(right_word++ - 1) = '\0'; /* Will restore later. */
+		else if (*(right_word + 1) != '=')
+			*right_word++ = '\0'; /* Will restore later. */
+		else
+			goto out;
+		dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
+			is_not ? "!" : "", right_word);
+		if (!strcmp(left_word, "grant_log")) {
+			if (entry) {
+				if (is_not ||
+				    entry->grant_log != TOMOYO_GRANTLOG_AUTO)
+					goto out;
+				else if (!strcmp(right_word, "yes"))
+					entry->grant_log = TOMOYO_GRANTLOG_YES;
+				else if (!strcmp(right_word, "no"))
+					entry->grant_log = TOMOYO_GRANTLOG_NO;
+				else
+					goto out;
+			}
+			continue;
+		}
+		if (!strncmp(left_word, "exec.argv[", 10)) {
+			if (!argv) {
+				e.argc++;
+				e.condc++;
+			} else {
+				e.argc--;
+				e.condc--;
+				left = TOMOYO_ARGV_ENTRY;
+				argv->is_not = is_not;
+				if (!tomoyo_parse_argv(left_word + 10,
+						       right_word, argv++))
+					goto out;
+			}
+			goto store_value;
+		}
+		if (!strncmp(left_word, "exec.envp[\"", 11)) {
+			if (!envp) {
+				e.envc++;
+				e.condc++;
+			} else {
+				e.envc--;
+				e.condc--;
+				left = TOMOYO_ENVP_ENTRY;
+				envp->is_not = is_not;
+				if (!tomoyo_parse_envp(left_word + 11,
+						       right_word, envp++))
+					goto out;
+			}
+			goto store_value;
+		}
+		left = tomoyo_condition_type(left_word);
+		dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
+			left);
+		if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
+			if (!numbers_p) {
+				e.numbers_count++;
+			} else {
+				e.numbers_count--;
+				left = TOMOYO_NUMBER_UNION;
+				param->data = left_word;
+				if (*left_word == '@' ||
+				    !tomoyo_parse_number_union(param,
+							       numbers_p++))
+					goto out;
+			}
+		}
+		if (!condp)
+			e.condc++;
+		else
+			e.condc--;
+		if (left == TOMOYO_EXEC_REALPATH ||
+		    left == TOMOYO_SYMLINK_TARGET) {
+			if (!names_p) {
+				e.names_count++;
+			} else {
+				e.names_count--;
+				right = TOMOYO_NAME_UNION;
+				param->data = right_word;
+				if (!tomoyo_parse_name_union_quoted(param,
+								    names_p++))
+					goto out;
+			}
+			goto store_value;
+		}
+		right = tomoyo_condition_type(right_word);
+		if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
+			if (!numbers_p) {
+				e.numbers_count++;
+			} else {
+				e.numbers_count--;
+				right = TOMOYO_NUMBER_UNION;
+				param->data = right_word;
+				if (!tomoyo_parse_number_union(param,
+							       numbers_p++))
+					goto out;
+			}
+		}
+store_value:
+		if (!condp) {
+			dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
+				"match=%u\n", __LINE__, left, right, !is_not);
+			continue;
+		}
+		condp->left = left;
+		condp->right = right;
+		condp->equals = !is_not;
+		dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
+			__LINE__, condp->left, condp->right,
+			condp->equals);
+		condp++;
+	}
+	dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
+		__LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
+		e.envc);
+	if (entry) {
+		BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
+		       e.condc);
+		return tomoyo_commit_condition(entry);
+	}
+	e.size = sizeof(*entry)
+		+ e.condc * sizeof(struct tomoyo_condition_element)
+		+ e.numbers_count * sizeof(struct tomoyo_number_union)
+		+ e.names_count * sizeof(struct tomoyo_name_union)
+		+ e.argc * sizeof(struct tomoyo_argv)
+		+ e.envc * sizeof(struct tomoyo_envp);
+	entry = kzalloc(e.size, GFP_NOFS);
+	if (!entry)
+		goto out2;
+	*entry = e;
+	e.transit = NULL;
+	condp = (struct tomoyo_condition_element *) (entry + 1);
+	numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
+	names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
+	argv = (struct tomoyo_argv *) (names_p + e.names_count);
+	envp = (struct tomoyo_envp *) (argv + e.argc);
+	{
+		bool flag = false;
+		for (pos = start_of_string; pos < end_of_string; pos++) {
+			if (*pos)
+				continue;
+			if (flag) /* Restore " ". */
+				*pos = ' ';
+			else if (*(pos + 1) == '=') /* Restore "!=". */
+				*pos = '!';
+			else /* Restore "=". */
+				*pos = '=';
+			flag = !flag;
+		}
+	}
+	goto rerun;
+out:
+	dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
+	if (entry) {
+		tomoyo_del_condition(&entry->head.list);
+		kfree(entry);
+	}
+out2:
+	tomoyo_put_name(e.transit);
+	return NULL;
+}
+
+/**
+ * tomoyo_get_attributes - Revalidate "struct inode".
+ *
+ * @obj: Pointer to "struct tomoyo_obj_info".
+ *
+ * Returns nothing.
+ */
+void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
+{
+	u8 i;
+	struct dentry *dentry = NULL;
+
+	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
+		struct inode *inode;
+		switch (i) {
+		case TOMOYO_PATH1:
+			dentry = obj->path1.dentry;
+			if (!dentry)
+				continue;
+			break;
+		case TOMOYO_PATH2:
+			dentry = obj->path2.dentry;
+			if (!dentry)
+				continue;
+			break;
+		default:
+			if (!dentry)
+				continue;
+			dentry = dget_parent(dentry);
+			break;
+		}
+		inode = dentry->d_inode;
+		if (inode) {
+			struct tomoyo_mini_stat *stat = &obj->stat[i];
+			stat->uid  = inode->i_uid;
+			stat->gid  = inode->i_gid;
+			stat->ino  = inode->i_ino;
+			stat->mode = inode->i_mode;
+			stat->dev  = inode->i_sb->s_dev;
+			stat->rdev = inode->i_rdev;
+			obj->stat_valid[i] = true;
+		}
+		if (i & 1) /* i == TOMOYO_PATH1_PARENT ||
+			      i == TOMOYO_PATH2_PARENT */
+			dput(dentry);
+	}
+}
+
+/**
+ * tomoyo_condition - Check condition part.
+ *
+ * @r:    Pointer to "struct tomoyo_request_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_condition(struct tomoyo_request_info *r,
+		      const struct tomoyo_condition *cond)
+{
+	u32 i;
+	unsigned long min_v[2] = { 0, 0 };
+	unsigned long max_v[2] = { 0, 0 };
+	const struct tomoyo_condition_element *condp;
+	const struct tomoyo_number_union *numbers_p;
+	const struct tomoyo_name_union *names_p;
+	const struct tomoyo_argv *argv;
+	const struct tomoyo_envp *envp;
+	struct tomoyo_obj_info *obj;
+	u16 condc;
+	u16 argc;
+	u16 envc;
+	struct linux_binprm *bprm = NULL;
+	if (!cond)
+		return true;
+	condc = cond->condc;
+	argc = cond->argc;
+	envc = cond->envc;
+	obj = r->obj;
+	if (r->ee)
+		bprm = r->ee->bprm;
+	if (!bprm && (argc || envc))
+		return false;
+	condp = (struct tomoyo_condition_element *) (cond + 1);
+	numbers_p = (const struct tomoyo_number_union *) (condp + condc);
+	names_p = (const struct tomoyo_name_union *)
+		(numbers_p + cond->numbers_count);
+	argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
+	envp = (const struct tomoyo_envp *) (argv + argc);
+	for (i = 0; i < condc; i++) {
+		const bool match = condp->equals;
+		const u8 left = condp->left;
+		const u8 right = condp->right;
+		bool is_bitop[2] = { false, false };
+		u8 j;
+		condp++;
+		/* Check argv[] and envp[] later. */
+		if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
+			continue;
+		/* Check string expressions. */
+		if (right == TOMOYO_NAME_UNION) {
+			const struct tomoyo_name_union *ptr = names_p++;
+			switch (left) {
+				struct tomoyo_path_info *symlink;
+				struct tomoyo_execve *ee;
+				struct file *file;
+			case TOMOYO_SYMLINK_TARGET:
+				symlink = obj ? obj->symlink_target : NULL;
+				if (!symlink ||
+				    !tomoyo_compare_name_union(symlink, ptr)
+				    == match)
+					goto out;
+				break;
+			case TOMOYO_EXEC_REALPATH:
+				ee = r->ee;
+				file = ee ? ee->bprm->file : NULL;
+				if (!tomoyo_scan_exec_realpath(file, ptr,
+							       match))
+					goto out;
+				break;
+			}
+			continue;
+		}
+		/* Check numeric or bit-op expressions. */
+		for (j = 0; j < 2; j++) {
+			const u8 index = j ? right : left;
+			unsigned long value = 0;
+			switch (index) {
+			case TOMOYO_TASK_UID:
+				value = current_uid();
+				break;
+			case TOMOYO_TASK_EUID:
+				value = current_euid();
+				break;
+			case TOMOYO_TASK_SUID:
+				value = current_suid();
+				break;
+			case TOMOYO_TASK_FSUID:
+				value = current_fsuid();
+				break;
+			case TOMOYO_TASK_GID:
+				value = current_gid();
+				break;
+			case TOMOYO_TASK_EGID:
+				value = current_egid();
+				break;
+			case TOMOYO_TASK_SGID:
+				value = current_sgid();
+				break;
+			case TOMOYO_TASK_FSGID:
+				value = current_fsgid();
+				break;
+			case TOMOYO_TASK_PID:
+				value = tomoyo_sys_getpid();
+				break;
+			case TOMOYO_TASK_PPID:
+				value = tomoyo_sys_getppid();
+				break;
+			case TOMOYO_TYPE_IS_SOCKET:
+				value = S_IFSOCK;
+				break;
+			case TOMOYO_TYPE_IS_SYMLINK:
+				value = S_IFLNK;
+				break;
+			case TOMOYO_TYPE_IS_FILE:
+				value = S_IFREG;
+				break;
+			case TOMOYO_TYPE_IS_BLOCK_DEV:
+				value = S_IFBLK;
+				break;
+			case TOMOYO_TYPE_IS_DIRECTORY:
+				value = S_IFDIR;
+				break;
+			case TOMOYO_TYPE_IS_CHAR_DEV:
+				value = S_IFCHR;
+				break;
+			case TOMOYO_TYPE_IS_FIFO:
+				value = S_IFIFO;
+				break;
+			case TOMOYO_MODE_SETUID:
+				value = S_ISUID;
+				break;
+			case TOMOYO_MODE_SETGID:
+				value = S_ISGID;
+				break;
+			case TOMOYO_MODE_STICKY:
+				value = S_ISVTX;
+				break;
+			case TOMOYO_MODE_OWNER_READ:
+				value = S_IRUSR;
+				break;
+			case TOMOYO_MODE_OWNER_WRITE:
+				value = S_IWUSR;
+				break;
+			case TOMOYO_MODE_OWNER_EXECUTE:
+				value = S_IXUSR;
+				break;
+			case TOMOYO_MODE_GROUP_READ:
+				value = S_IRGRP;
+				break;
+			case TOMOYO_MODE_GROUP_WRITE:
+				value = S_IWGRP;
+				break;
+			case TOMOYO_MODE_GROUP_EXECUTE:
+				value = S_IXGRP;
+				break;
+			case TOMOYO_MODE_OTHERS_READ:
+				value = S_IROTH;
+				break;
+			case TOMOYO_MODE_OTHERS_WRITE:
+				value = S_IWOTH;
+				break;
+			case TOMOYO_MODE_OTHERS_EXECUTE:
+				value = S_IXOTH;
+				break;
+			case TOMOYO_EXEC_ARGC:
+				if (!bprm)
+					goto out;
+				value = bprm->argc;
+				break;
+			case TOMOYO_EXEC_ENVC:
+				if (!bprm)
+					goto out;
+				value = bprm->envc;
+				break;
+			case TOMOYO_NUMBER_UNION:
+				/* Fetch values later. */
+				break;
+			default:
+				if (!obj)
+					goto out;
+				if (!obj->validate_done) {
+					tomoyo_get_attributes(obj);
+					obj->validate_done = true;
+				}
+				{
+					u8 stat_index;
+					struct tomoyo_mini_stat *stat;
+					switch (index) {
+					case TOMOYO_PATH1_UID:
+					case TOMOYO_PATH1_GID:
+					case TOMOYO_PATH1_INO:
+					case TOMOYO_PATH1_MAJOR:
+					case TOMOYO_PATH1_MINOR:
+					case TOMOYO_PATH1_TYPE:
+					case TOMOYO_PATH1_DEV_MAJOR:
+					case TOMOYO_PATH1_DEV_MINOR:
+					case TOMOYO_PATH1_PERM:
+						stat_index = TOMOYO_PATH1;
+						break;
+					case TOMOYO_PATH2_UID:
+					case TOMOYO_PATH2_GID:
+					case TOMOYO_PATH2_INO:
+					case TOMOYO_PATH2_MAJOR:
+					case TOMOYO_PATH2_MINOR:
+					case TOMOYO_PATH2_TYPE:
+					case TOMOYO_PATH2_DEV_MAJOR:
+					case TOMOYO_PATH2_DEV_MINOR:
+					case TOMOYO_PATH2_PERM:
+						stat_index = TOMOYO_PATH2;
+						break;
+					case TOMOYO_PATH1_PARENT_UID:
+					case TOMOYO_PATH1_PARENT_GID:
+					case TOMOYO_PATH1_PARENT_INO:
+					case TOMOYO_PATH1_PARENT_PERM:
+						stat_index =
+							TOMOYO_PATH1_PARENT;
+						break;
+					case TOMOYO_PATH2_PARENT_UID:
+					case TOMOYO_PATH2_PARENT_GID:
+					case TOMOYO_PATH2_PARENT_INO:
+					case TOMOYO_PATH2_PARENT_PERM:
+						stat_index =
+							TOMOYO_PATH2_PARENT;
+						break;
+					default:
+						goto out;
+					}
+					if (!obj->stat_valid[stat_index])
+						goto out;
+					stat = &obj->stat[stat_index];
+					switch (index) {
+					case TOMOYO_PATH1_UID:
+					case TOMOYO_PATH2_UID:
+					case TOMOYO_PATH1_PARENT_UID:
+					case TOMOYO_PATH2_PARENT_UID:
+						value = stat->uid;
+						break;
+					case TOMOYO_PATH1_GID:
+					case TOMOYO_PATH2_GID:
+					case TOMOYO_PATH1_PARENT_GID:
+					case TOMOYO_PATH2_PARENT_GID:
+						value = stat->gid;
+						break;
+					case TOMOYO_PATH1_INO:
+					case TOMOYO_PATH2_INO:
+					case TOMOYO_PATH1_PARENT_INO:
+					case TOMOYO_PATH2_PARENT_INO:
+						value = stat->ino;
+						break;
+					case TOMOYO_PATH1_MAJOR:
+					case TOMOYO_PATH2_MAJOR:
+						value = MAJOR(stat->dev);
+						break;
+					case TOMOYO_PATH1_MINOR:
+					case TOMOYO_PATH2_MINOR:
+						value = MINOR(stat->dev);
+						break;
+					case TOMOYO_PATH1_TYPE:
+					case TOMOYO_PATH2_TYPE:
+						value = stat->mode & S_IFMT;
+						break;
+					case TOMOYO_PATH1_DEV_MAJOR:
+					case TOMOYO_PATH2_DEV_MAJOR:
+						value = MAJOR(stat->rdev);
+						break;
+					case TOMOYO_PATH1_DEV_MINOR:
+					case TOMOYO_PATH2_DEV_MINOR:
+						value = MINOR(stat->rdev);
+						break;
+					case TOMOYO_PATH1_PERM:
+					case TOMOYO_PATH2_PERM:
+					case TOMOYO_PATH1_PARENT_PERM:
+					case TOMOYO_PATH2_PARENT_PERM:
+						value = stat->mode & S_IALLUGO;
+						break;
+					}
+				}
+				break;
+			}
+			max_v[j] = value;
+			min_v[j] = value;
+			switch (index) {
+			case TOMOYO_MODE_SETUID:
+			case TOMOYO_MODE_SETGID:
+			case TOMOYO_MODE_STICKY:
+			case TOMOYO_MODE_OWNER_READ:
+			case TOMOYO_MODE_OWNER_WRITE:
+			case TOMOYO_MODE_OWNER_EXECUTE:
+			case TOMOYO_MODE_GROUP_READ:
+			case TOMOYO_MODE_GROUP_WRITE:
+			case TOMOYO_MODE_GROUP_EXECUTE:
+			case TOMOYO_MODE_OTHERS_READ:
+			case TOMOYO_MODE_OTHERS_WRITE:
+			case TOMOYO_MODE_OTHERS_EXECUTE:
+				is_bitop[j] = true;
+			}
+		}
+		if (left == TOMOYO_NUMBER_UNION) {
+			/* Fetch values now. */
+			const struct tomoyo_number_union *ptr = numbers_p++;
+			min_v[0] = ptr->values[0];
+			max_v[0] = ptr->values[1];
+		}
+		if (right == TOMOYO_NUMBER_UNION) {
+			/* Fetch values now. */
+			const struct tomoyo_number_union *ptr = numbers_p++;
+			if (ptr->group) {
+				if (tomoyo_number_matches_group(min_v[0],
+								max_v[0],
+								ptr->group)
+				    == match)
+					continue;
+			} else {
+				if ((min_v[0] <= ptr->values[1] &&
+				     max_v[0] >= ptr->values[0]) == match)
+					continue;
+			}
+			goto out;
+		}
+		/*
+		 * Bit operation is valid only when counterpart value
+		 * represents permission.
+		 */
+		if (is_bitop[0] && is_bitop[1]) {
+			goto out;
+		} else if (is_bitop[0]) {
+			switch (right) {
+			case TOMOYO_PATH1_PERM:
+			case TOMOYO_PATH1_PARENT_PERM:
+			case TOMOYO_PATH2_PERM:
+			case TOMOYO_PATH2_PARENT_PERM:
+				if (!(max_v[0] & max_v[1]) == !match)
+					continue;
+			}
+			goto out;
+		} else if (is_bitop[1]) {
+			switch (left) {
+			case TOMOYO_PATH1_PERM:
+			case TOMOYO_PATH1_PARENT_PERM:
+			case TOMOYO_PATH2_PERM:
+			case TOMOYO_PATH2_PARENT_PERM:
+				if (!(max_v[0] & max_v[1]) == !match)
+					continue;
+			}
+			goto out;
+		}
+		/* Normal value range comparison. */
+		if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
+			continue;
+out:
+		return false;
+	}
+	/* Check argv[] and envp[] now. */
+	if (r->ee && (argc || envc))
+		return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
+	return true;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/domain.c b/ap/os/linux/linux-3.4.x/security/tomoyo/domain.c
new file mode 100644
index 0000000..3865145
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/domain.c
@@ -0,0 +1,901 @@
+/*
+ * security/tomoyo/domain.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/binfmts.h>
+#include <linux/slab.h>
+
+/* Variables definitions.*/
+
+/* The initial domain. */
+struct tomoyo_domain_info tomoyo_kernel_domain;
+
+/**
+ * tomoyo_update_policy - Update an entry for exception policy.
+ *
+ * @new_entry:       Pointer to "struct tomoyo_acl_info".
+ * @size:            Size of @new_entry in bytes.
+ * @param:           Pointer to "struct tomoyo_acl_param".
+ * @check_duplicate: Callback function to find duplicated entry.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
+			 struct tomoyo_acl_param *param,
+			 bool (*check_duplicate) (const struct tomoyo_acl_head
+						  *,
+						  const struct tomoyo_acl_head
+						  *))
+{
+	int error = param->is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_acl_head *entry;
+	struct list_head *list = param->list;
+
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		return -ENOMEM;
+	list_for_each_entry_rcu(entry, list, list) {
+		if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
+			continue;
+		if (!check_duplicate(entry, new_entry))
+			continue;
+		entry->is_deleted = param->is_delete;
+		error = 0;
+		break;
+	}
+	if (error && !param->is_delete) {
+		entry = tomoyo_commit_ok(new_entry, size);
+		if (entry) {
+			list_add_tail_rcu(&entry->list, list);
+			error = 0;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+	return error;
+}
+
+/**
+ * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
+					const struct tomoyo_acl_info *b)
+{
+	return a->type == b->type && a->cond == b->cond;
+}
+
+/**
+ * tomoyo_update_domain - Update an entry for domain policy.
+ *
+ * @new_entry:       Pointer to "struct tomoyo_acl_info".
+ * @size:            Size of @new_entry in bytes.
+ * @param:           Pointer to "struct tomoyo_acl_param".
+ * @check_duplicate: Callback function to find duplicated entry.
+ * @merge_duplicate: Callback function to merge duplicated entry.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
+			 struct tomoyo_acl_param *param,
+			 bool (*check_duplicate) (const struct tomoyo_acl_info
+						  *,
+						  const struct tomoyo_acl_info
+						  *),
+			 bool (*merge_duplicate) (struct tomoyo_acl_info *,
+						  struct tomoyo_acl_info *,
+						  const bool))
+{
+	const bool is_delete = param->is_delete;
+	int error = is_delete ? -ENOENT : -ENOMEM;
+	struct tomoyo_acl_info *entry;
+	struct list_head * const list = param->list;
+
+	if (param->data[0]) {
+		new_entry->cond = tomoyo_get_condition(param);
+		if (!new_entry->cond)
+			return -EINVAL;
+		/*
+		 * Domain transition preference is allowed for only
+		 * "file execute" entries.
+		 */
+		if (new_entry->cond->transit &&
+		    !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
+		      container_of(new_entry, struct tomoyo_path_acl, head)
+		      ->perm == 1 << TOMOYO_TYPE_EXECUTE))
+			goto out;
+	}
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	list_for_each_entry_rcu(entry, list, list) {
+		if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
+			continue;
+		if (!tomoyo_same_acl_head(entry, new_entry) ||
+		    !check_duplicate(entry, new_entry))
+			continue;
+		if (merge_duplicate)
+			entry->is_deleted = merge_duplicate(entry, new_entry,
+							    is_delete);
+		else
+			entry->is_deleted = is_delete;
+		error = 0;
+		break;
+	}
+	if (error && !is_delete) {
+		entry = tomoyo_commit_ok(new_entry, size);
+		if (entry) {
+			list_add_tail_rcu(&entry->list, list);
+			error = 0;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+out:
+	tomoyo_put_condition(new_entry->cond);
+	return error;
+}
+
+/**
+ * tomoyo_check_acl - Do permission check.
+ *
+ * @r:           Pointer to "struct tomoyo_request_info".
+ * @check_entry: Callback function to check type specific parameters.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+void tomoyo_check_acl(struct tomoyo_request_info *r,
+		      bool (*check_entry) (struct tomoyo_request_info *,
+					   const struct tomoyo_acl_info *))
+{
+	const struct tomoyo_domain_info *domain = r->domain;
+	struct tomoyo_acl_info *ptr;
+	bool retried = false;
+	const struct list_head *list = &domain->acl_info_list;
+
+retry:
+	list_for_each_entry_rcu(ptr, list, list) {
+		if (ptr->is_deleted || ptr->type != r->param_type)
+			continue;
+		if (!check_entry(r, ptr))
+			continue;
+		if (!tomoyo_condition(r, ptr->cond))
+			continue;
+		r->matched_acl = ptr;
+		r->granted = true;
+		return;
+	}
+	if (!retried) {
+		retried = true;
+		list = &domain->ns->acl_group[domain->group];
+		goto retry;
+	}
+	r->granted = false;
+}
+
+/* The list for "struct tomoyo_domain_info". */
+LIST_HEAD(tomoyo_domain_list);
+
+/**
+ * tomoyo_last_word - Get last component of a domainname.
+ *
+ * @name: Domainname to check.
+ *
+ * Returns the last word of @domainname.
+ */
+static const char *tomoyo_last_word(const char *name)
+{
+	const char *cp = strrchr(name, ' ');
+	if (cp)
+		return cp + 1;
+	return name;
+}
+
+/**
+ * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
+					   const struct tomoyo_acl_head *b)
+{
+	const struct tomoyo_transition_control *p1 = container_of(a,
+								  typeof(*p1),
+								  head);
+	const struct tomoyo_transition_control *p2 = container_of(b,
+								  typeof(*p2),
+								  head);
+	return p1->type == p2->type && p1->is_last_name == p2->is_last_name
+		&& p1->domainname == p2->domainname
+		&& p1->program == p2->program;
+}
+
+/**
+ * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @type:  Type of this entry.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
+				    const u8 type)
+{
+	struct tomoyo_transition_control e = { .type = type };
+	int error = param->is_delete ? -ENOENT : -ENOMEM;
+	char *program = param->data;
+	char *domainname = strstr(program, " from ");
+	if (domainname) {
+		*domainname = '\0';
+		domainname += 6;
+	} else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
+		   type == TOMOYO_TRANSITION_CONTROL_KEEP) {
+		domainname = program;
+		program = NULL;
+	}
+	if (program && strcmp(program, "any")) {
+		if (!tomoyo_correct_path(program))
+			return -EINVAL;
+		e.program = tomoyo_get_name(program);
+		if (!e.program)
+			goto out;
+	}
+	if (domainname && strcmp(domainname, "any")) {
+		if (!tomoyo_correct_domain(domainname)) {
+			if (!tomoyo_correct_path(domainname))
+				goto out;
+			e.is_last_name = true;
+		}
+		e.domainname = tomoyo_get_name(domainname);
+		if (!e.domainname)
+			goto out;
+	}
+	param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
+	error = tomoyo_update_policy(&e.head, sizeof(e), param,
+				     tomoyo_same_transition_control);
+out:
+	tomoyo_put_name(e.domainname);
+	tomoyo_put_name(e.program);
+	return error;
+}
+
+/**
+ * tomoyo_scan_transition - Try to find specific domain transition type.
+ *
+ * @list:       Pointer to "struct list_head".
+ * @domainname: The name of current domain.
+ * @program:    The name of requested program.
+ * @last_name:  The last component of @domainname.
+ * @type:       One of values in "enum tomoyo_transition_type".
+ *
+ * Returns true if found one, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static inline bool tomoyo_scan_transition
+(const struct list_head *list, const struct tomoyo_path_info *domainname,
+ const struct tomoyo_path_info *program, const char *last_name,
+ const enum tomoyo_transition_type type)
+{
+	const struct tomoyo_transition_control *ptr;
+	list_for_each_entry_rcu(ptr, list, head.list) {
+		if (ptr->head.is_deleted || ptr->type != type)
+			continue;
+		if (ptr->domainname) {
+			if (!ptr->is_last_name) {
+				if (ptr->domainname != domainname)
+					continue;
+			} else {
+				/*
+				 * Use direct strcmp() since this is
+				 * unlikely used.
+				 */
+				if (strcmp(ptr->domainname->name, last_name))
+					continue;
+			}
+		}
+		if (ptr->program && tomoyo_pathcmp(ptr->program, program))
+			continue;
+		return true;
+	}
+	return false;
+}
+
+/**
+ * tomoyo_transition_type - Get domain transition type.
+ *
+ * @ns:         Pointer to "struct tomoyo_policy_namespace".
+ * @domainname: The name of current domain.
+ * @program:    The name of requested program.
+ *
+ * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
+ * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
+ * executing @program reinitializes domain transition within that namespace,
+ * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
+ * others otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static enum tomoyo_transition_type tomoyo_transition_type
+(const struct tomoyo_policy_namespace *ns,
+ const struct tomoyo_path_info *domainname,
+ const struct tomoyo_path_info *program)
+{
+	const char *last_name = tomoyo_last_word(domainname->name);
+	enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
+	while (type < TOMOYO_MAX_TRANSITION_TYPE) {
+		const struct list_head * const list =
+			&ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
+		if (!tomoyo_scan_transition(list, domainname, program,
+					    last_name, type)) {
+			type++;
+			continue;
+		}
+		if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
+		    type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
+			break;
+		/*
+		 * Do not check for reset_domain if no_reset_domain matched.
+		 * Do not check for initialize_domain if no_initialize_domain
+		 * matched.
+		 */
+		type++;
+		type++;
+	}
+	return type;
+}
+
+/**
+ * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
+				   const struct tomoyo_acl_head *b)
+{
+	const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
+							  head);
+	const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
+							  head);
+	return p1->original_name == p2->original_name &&
+		p1->aggregated_name == p2->aggregated_name;
+}
+
+/**
+ * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
+{
+	struct tomoyo_aggregator e = { };
+	int error = param->is_delete ? -ENOENT : -ENOMEM;
+	const char *original_name = tomoyo_read_token(param);
+	const char *aggregated_name = tomoyo_read_token(param);
+	if (!tomoyo_correct_word(original_name) ||
+	    !tomoyo_correct_path(aggregated_name))
+		return -EINVAL;
+	e.original_name = tomoyo_get_name(original_name);
+	e.aggregated_name = tomoyo_get_name(aggregated_name);
+	if (!e.original_name || !e.aggregated_name ||
+	    e.aggregated_name->is_patterned) /* No patterns allowed. */
+		goto out;
+	param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
+	error = tomoyo_update_policy(&e.head, sizeof(e), param,
+				     tomoyo_same_aggregator);
+out:
+	tomoyo_put_name(e.original_name);
+	tomoyo_put_name(e.aggregated_name);
+	return error;
+}
+
+/**
+ * tomoyo_find_namespace - Find specified namespace.
+ *
+ * @name: Name of namespace to find.
+ * @len:  Length of @name.
+ *
+ * Returns pointer to "struct tomoyo_policy_namespace" if found,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static struct tomoyo_policy_namespace *tomoyo_find_namespace
+(const char *name, const unsigned int len)
+{
+	struct tomoyo_policy_namespace *ns;
+	list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
+		if (strncmp(name, ns->name, len) ||
+		    (name[len] && name[len] != ' '))
+			continue;
+		return ns;
+	}
+	return NULL;
+}
+
+/**
+ * tomoyo_assign_namespace - Create a new namespace.
+ *
+ * @domainname: Name of namespace to create.
+ *
+ * Returns pointer to "struct tomoyo_policy_namespace" on success,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
+{
+	struct tomoyo_policy_namespace *ptr;
+	struct tomoyo_policy_namespace *entry;
+	const char *cp = domainname;
+	unsigned int len = 0;
+	while (*cp && *cp++ != ' ')
+		len++;
+	ptr = tomoyo_find_namespace(domainname, len);
+	if (ptr)
+		return ptr;
+	if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
+		return NULL;
+	entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
+	if (!entry)
+		return NULL;
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	ptr = tomoyo_find_namespace(domainname, len);
+	if (!ptr && tomoyo_memory_ok(entry)) {
+		char *name = (char *) (entry + 1);
+		ptr = entry;
+		memmove(name, domainname, len);
+		name[len] = '\0';
+		entry->name = name;
+		tomoyo_init_policy_namespace(entry);
+		entry = NULL;
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+out:
+	kfree(entry);
+	return ptr;
+}
+
+/**
+ * tomoyo_namespace_jump - Check for namespace jump.
+ *
+ * @domainname: Name of domain.
+ *
+ * Returns true if namespace differs, false otherwise.
+ */
+static bool tomoyo_namespace_jump(const char *domainname)
+{
+	const char *namespace = tomoyo_current_namespace()->name;
+	const int len = strlen(namespace);
+	return strncmp(domainname, namespace, len) ||
+		(domainname[len] && domainname[len] != ' ');
+}
+
+/**
+ * tomoyo_assign_domain - Create a domain or a namespace.
+ *
+ * @domainname: The name of domain.
+ * @transit:    True if transit to domain found or created.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+						const bool transit)
+{
+	struct tomoyo_domain_info e = { };
+	struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
+	bool created = false;
+	if (entry) {
+		if (transit) {
+			/*
+			 * Since namespace is created at runtime, profiles may
+			 * not be created by the moment the process transits to
+			 * that domain. Do not perform domain transition if
+			 * profile for that domain is not yet created.
+			 */
+			if (tomoyo_policy_loaded &&
+			    !entry->ns->profile_ptr[entry->profile])
+				return NULL;
+		}
+		return entry;
+	}
+	/* Requested domain does not exist. */
+	/* Don't create requested domain if domainname is invalid. */
+	if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
+	    !tomoyo_correct_domain(domainname))
+		return NULL;
+	/*
+	 * Since definition of profiles and acl_groups may differ across
+	 * namespaces, do not inherit "use_profile" and "use_group" settings
+	 * by automatically creating requested domain upon domain transition.
+	 */
+	if (transit && tomoyo_namespace_jump(domainname))
+		return NULL;
+	e.ns = tomoyo_assign_namespace(domainname);
+	if (!e.ns)
+		return NULL;
+	/*
+	 * "use_profile" and "use_group" settings for automatically created
+	 * domains are inherited from current domain. These are 0 for manually
+	 * created domains.
+	 */
+	if (transit) {
+		const struct tomoyo_domain_info *domain = tomoyo_domain();
+		e.profile = domain->profile;
+		e.group = domain->group;
+	}
+	e.domainname = tomoyo_get_name(domainname);
+	if (!e.domainname)
+		return NULL;
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	entry = tomoyo_find_domain(domainname);
+	if (!entry) {
+		entry = tomoyo_commit_ok(&e, sizeof(e));
+		if (entry) {
+			INIT_LIST_HEAD(&entry->acl_info_list);
+			list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
+			created = true;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+out:
+	tomoyo_put_name(e.domainname);
+	if (entry && transit) {
+		if (created) {
+			struct tomoyo_request_info r;
+			tomoyo_init_request_info(&r, entry,
+						 TOMOYO_MAC_FILE_EXECUTE);
+			r.granted = false;
+			tomoyo_write_log(&r, "use_profile %u\n",
+					 entry->profile);
+			tomoyo_write_log(&r, "use_group %u\n", entry->group);
+			tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
+		}
+	}
+	return entry;
+}
+
+/**
+ * tomoyo_environ - Check permission for environment variable names.
+ *
+ * @ee: Pointer to "struct tomoyo_execve".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_environ(struct tomoyo_execve *ee)
+{
+	struct tomoyo_request_info *r = &ee->r;
+	struct linux_binprm *bprm = ee->bprm;
+	/* env_page.data is allocated by tomoyo_dump_page(). */
+	struct tomoyo_page_dump env_page = { };
+	char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
+	int arg_len = 0;
+	unsigned long pos = bprm->p;
+	int offset = pos % PAGE_SIZE;
+	int argv_count = bprm->argc;
+	int envp_count = bprm->envc;
+	int error = -ENOMEM;
+
+	ee->r.type = TOMOYO_MAC_ENVIRON;
+	ee->r.profile = r->domain->profile;
+	ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
+				     TOMOYO_MAC_ENVIRON);
+	if (!r->mode || !envp_count)
+		return 0;
+	arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
+	if (!arg_ptr)
+		goto out;
+	while (error == -ENOMEM) {
+		if (!tomoyo_dump_page(bprm, pos, &env_page))
+			goto out;
+		pos += PAGE_SIZE - offset;
+		/* Read. */
+		while (argv_count && offset < PAGE_SIZE) {
+			if (!env_page.data[offset++])
+				argv_count--;
+		}
+		if (argv_count) {
+			offset = 0;
+			continue;
+		}
+		while (offset < PAGE_SIZE) {
+			const unsigned char c = env_page.data[offset++];
+
+			if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
+				if (c == '=') {
+					arg_ptr[arg_len++] = '\0';
+				} else if (c == '\\') {
+					arg_ptr[arg_len++] = '\\';
+					arg_ptr[arg_len++] = '\\';
+				} else if (c > ' ' && c < 127) {
+					arg_ptr[arg_len++] = c;
+				} else {
+					arg_ptr[arg_len++] = '\\';
+					arg_ptr[arg_len++] = (c >> 6) + '0';
+					arg_ptr[arg_len++]
+						= ((c >> 3) & 7) + '0';
+					arg_ptr[arg_len++] = (c & 7) + '0';
+				}
+			} else {
+				arg_ptr[arg_len] = '\0';
+			}
+			if (c)
+				continue;
+			if (tomoyo_env_perm(r, arg_ptr)) {
+				error = -EPERM;
+				break;
+			}
+			if (!--envp_count) {
+				error = 0;
+				break;
+			}
+			arg_len = 0;
+		}
+		offset = 0;
+	}
+out:
+	if (r->mode != TOMOYO_CONFIG_ENFORCING)
+		error = 0;
+	kfree(env_page.data);
+	kfree(arg_ptr);
+	return error;
+}
+
+/**
+ * tomoyo_find_next_domain - Find a domain.
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_find_next_domain(struct linux_binprm *bprm)
+{
+	struct tomoyo_domain_info *old_domain = tomoyo_domain();
+	struct tomoyo_domain_info *domain = NULL;
+	const char *original_name = bprm->filename;
+	int retval = -ENOMEM;
+	bool reject_on_transition_failure = false;
+	const struct tomoyo_path_info *candidate;
+	struct tomoyo_path_info exename;
+	struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
+
+	if (!ee)
+		return -ENOMEM;
+	ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
+	if (!ee->tmp) {
+		kfree(ee);
+		return -ENOMEM;
+	}
+	/* ee->dump->data is allocated by tomoyo_dump_page(). */
+	tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+	ee->r.ee = ee;
+	ee->bprm = bprm;
+	ee->r.obj = &ee->obj;
+	ee->obj.path1 = bprm->file->f_path;
+	/* Get symlink's pathname of program. */
+	retval = -ENOENT;
+	exename.name = tomoyo_realpath_nofollow(original_name);
+	if (!exename.name)
+		goto out;
+	tomoyo_fill_path_info(&exename);
+retry:
+	/* Check 'aggregator' directive. */
+	{
+		struct tomoyo_aggregator *ptr;
+		struct list_head *list =
+			&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
+		/* Check 'aggregator' directive. */
+		candidate = &exename;
+		list_for_each_entry_rcu(ptr, list, head.list) {
+			if (ptr->head.is_deleted ||
+			    !tomoyo_path_matches_pattern(&exename,
+							 ptr->original_name))
+				continue;
+			candidate = ptr->aggregated_name;
+			break;
+		}
+	}
+
+	/* Check execute permission. */
+	retval = tomoyo_execute_permission(&ee->r, candidate);
+	if (retval == TOMOYO_RETRY_REQUEST)
+		goto retry;
+	if (retval < 0)
+		goto out;
+	/*
+	 * To be able to specify domainnames with wildcards, use the
+	 * pathname specified in the policy (which may contain
+	 * wildcard) rather than the pathname passed to execve()
+	 * (which never contains wildcard).
+	 */
+	if (ee->r.param.path.matched_path)
+		candidate = ee->r.param.path.matched_path;
+
+	/*
+	 * Check for domain transition preference if "file execute" matched.
+	 * If preference is given, make do_execve() fail if domain transition
+	 * has failed, for domain transition preference should be used with
+	 * destination domain defined.
+	 */
+	if (ee->transition) {
+		const char *domainname = ee->transition->name;
+		reject_on_transition_failure = true;
+		if (!strcmp(domainname, "keep"))
+			goto force_keep_domain;
+		if (!strcmp(domainname, "child"))
+			goto force_child_domain;
+		if (!strcmp(domainname, "reset"))
+			goto force_reset_domain;
+		if (!strcmp(domainname, "initialize"))
+			goto force_initialize_domain;
+		if (!strcmp(domainname, "parent")) {
+			char *cp;
+			strncpy(ee->tmp, old_domain->domainname->name,
+				TOMOYO_EXEC_TMPSIZE - 1);
+			cp = strrchr(ee->tmp, ' ');
+			if (cp)
+				*cp = '\0';
+		} else if (*domainname == '<')
+			strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
+		else
+			snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+				 old_domain->domainname->name, domainname);
+		goto force_jump_domain;
+	}
+	/*
+	 * No domain transition preference specified.
+	 * Calculate domain to transit to.
+	 */
+	switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
+				       candidate)) {
+	case TOMOYO_TRANSITION_CONTROL_RESET:
+force_reset_domain:
+		/* Transit to the root of specified namespace. */
+		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
+			 candidate->name);
+		/*
+		 * Make do_execve() fail if domain transition across namespaces
+		 * has failed.
+		 */
+		reject_on_transition_failure = true;
+		break;
+	case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
+force_initialize_domain:
+		/* Transit to the child of current namespace's root. */
+		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+			 old_domain->ns->name, candidate->name);
+		break;
+	case TOMOYO_TRANSITION_CONTROL_KEEP:
+force_keep_domain:
+		/* Keep current domain. */
+		domain = old_domain;
+		break;
+	default:
+		if (old_domain == &tomoyo_kernel_domain &&
+		    !tomoyo_policy_loaded) {
+			/*
+			 * Needn't to transit from kernel domain before
+			 * starting /sbin/init. But transit from kernel domain
+			 * if executing initializers because they might start
+			 * before /sbin/init.
+			 */
+			domain = old_domain;
+			break;
+		}
+force_child_domain:
+		/* Normal domain transition. */
+		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+			 old_domain->domainname->name, candidate->name);
+		break;
+	}
+force_jump_domain:
+	if (!domain)
+		domain = tomoyo_assign_domain(ee->tmp, true);
+	if (domain)
+		retval = 0;
+	else if (reject_on_transition_failure) {
+		printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
+		       ee->tmp);
+		retval = -ENOMEM;
+	} else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
+		retval = -ENOMEM;
+	else {
+		retval = 0;
+		if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
+			old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
+			ee->r.granted = false;
+			tomoyo_write_log(&ee->r, "%s", tomoyo_dif
+					 [TOMOYO_DIF_TRANSITION_FAILED]);
+			printk(KERN_WARNING
+			       "ERROR: Domain '%s' not defined.\n", ee->tmp);
+		}
+	}
+ out:
+	if (!domain)
+		domain = old_domain;
+	/* Update reference count on "struct tomoyo_domain_info". */
+	atomic_inc(&domain->users);
+	bprm->cred->security = domain;
+	kfree(exename.name);
+	if (!retval) {
+		ee->r.domain = domain;
+		retval = tomoyo_environ(ee);
+	}
+	kfree(ee->tmp);
+	kfree(ee->dump.data);
+	kfree(ee);
+	return retval;
+}
+
+/**
+ * tomoyo_dump_page - Dump a page to buffer.
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ * @pos:  Location to dump.
+ * @dump: Poiner to "struct tomoyo_page_dump".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
+		      struct tomoyo_page_dump *dump)
+{
+	struct page *page;
+
+	/* dump->data is released by tomoyo_find_next_domain(). */
+	if (!dump->data) {
+		dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
+		if (!dump->data)
+			return false;
+	}
+	/* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
+#ifdef CONFIG_MMU
+	if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
+		return false;
+#else
+	page = bprm->page[pos / PAGE_SIZE];
+#endif
+	if (page != dump->page) {
+		const unsigned int offset = pos % PAGE_SIZE;
+		/*
+		 * Maybe kmap()/kunmap() should be used here.
+		 * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
+		 * So do I.
+		 */
+		char *kaddr = kmap_atomic(page);
+
+		dump->page = page;
+		memcpy(dump->data + offset, kaddr + offset,
+		       PAGE_SIZE - offset);
+		kunmap_atomic(kaddr);
+	}
+	/* Same with put_arg_page(page) in fs/exec.c */
+#ifdef CONFIG_MMU
+	put_page(page);
+#endif
+	return true;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/environ.c b/ap/os/linux/linux-3.4.x/security/tomoyo/environ.c
new file mode 100644
index 0000000..ad4c6e1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/environ.c
@@ -0,0 +1,122 @@
+/*
+ * security/tomoyo/environ.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+/**
+ * tomoyo_check_env_acl - Check permission for environment variable's name.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_env_acl(struct tomoyo_request_info *r,
+				 const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_env_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+
+	return tomoyo_path_matches_pattern(r->param.environ.name, acl->env);
+}
+
+/**
+ * tomoyo_audit_env_log - Audit environment variable name log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_env_log(struct tomoyo_request_info *r)
+{
+	return tomoyo_supervisor(r, "misc env %s\n",
+				 r->param.environ.name->name);
+}
+
+/**
+ * tomoyo_env_perm - Check permission for environment variable's name.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @env: The name of environment variable.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env)
+{
+	struct tomoyo_path_info environ;
+	int error;
+
+	if (!env || !*env)
+		return 0;
+	environ.name = env;
+	tomoyo_fill_path_info(&environ);
+	r->param_type = TOMOYO_TYPE_ENV_ACL;
+	r->param.environ.name = &environ;
+	do {
+		tomoyo_check_acl(r, tomoyo_check_env_acl);
+		error = tomoyo_audit_env_log(r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+	return error;
+}
+
+/**
+ * tomoyo_same_env_acl - Check for duplicated "struct tomoyo_env_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_env_acl(const struct tomoyo_acl_info *a,
+				const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_env_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_env_acl *p2 = container_of(b, typeof(*p2), head);
+
+	return p1->env == p2->env;
+}
+
+/**
+ * tomoyo_write_env - Write "struct tomoyo_env_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_env(struct tomoyo_acl_param *param)
+{
+	struct tomoyo_env_acl e = { .head.type = TOMOYO_TYPE_ENV_ACL };
+	int error = -ENOMEM;
+	const char *data = tomoyo_read_token(param);
+
+	if (!tomoyo_correct_word(data) || strchr(data, '='))
+		return -EINVAL;
+	e.env = tomoyo_get_name(data);
+	if (!e.env)
+		return error;
+	error = tomoyo_update_domain(&e.head, sizeof(e), param,
+				  tomoyo_same_env_acl, NULL);
+	tomoyo_put_name(e.env);
+	return error;
+}
+
+/**
+ * tomoyo_write_misc - Update environment variable list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_misc(struct tomoyo_acl_param *param)
+{
+	if (tomoyo_str_starts(&param->data, "env "))
+		return tomoyo_write_env(param);
+	return -EINVAL;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/file.c b/ap/os/linux/linux-3.4.x/security/tomoyo/file.c
new file mode 100644
index 0000000..4003907
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/file.c
@@ -0,0 +1,1026 @@
+/*
+ * security/tomoyo/file.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/*
+ * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
+ */
+static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
+	[TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
+	[TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
+	[TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
+	[TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
+	[TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
+	[TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
+	[TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
+	[TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
+	[TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
+	[TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
+	[TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
+};
+
+/*
+ * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
+ */
+const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
+	[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
+	[TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
+};
+
+/*
+ * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
+ */
+const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+	[TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
+	[TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
+	[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
+};
+
+/*
+ * Mapping table from "enum tomoyo_path_number_acl_index" to
+ * "enum tomoyo_mac_index".
+ */
+const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+	[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
+	[TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
+	[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
+	[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
+	[TOMOYO_TYPE_IOCTL]  = TOMOYO_MAC_FILE_IOCTL,
+	[TOMOYO_TYPE_CHMOD]  = TOMOYO_MAC_FILE_CHMOD,
+	[TOMOYO_TYPE_CHOWN]  = TOMOYO_MAC_FILE_CHOWN,
+	[TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
+};
+
+/**
+ * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
+ *
+ * @ptr: Pointer to "struct tomoyo_name_union".
+ *
+ * Returns nothing.
+ */
+void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
+{
+	tomoyo_put_group(ptr->group);
+	tomoyo_put_name(ptr->filename);
+}
+
+/**
+ * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
+ *
+ * @name: Pointer to "struct tomoyo_path_info".
+ * @ptr:  Pointer to "struct tomoyo_name_union".
+ *
+ * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
+ */
+const struct tomoyo_path_info *
+tomoyo_compare_name_union(const struct tomoyo_path_info *name,
+			  const struct tomoyo_name_union *ptr)
+{
+	if (ptr->group)
+		return tomoyo_path_matches_group(name, ptr->group);
+	if (tomoyo_path_matches_pattern(name, ptr->filename))
+		return ptr->filename;
+	return NULL;
+}
+
+/**
+ * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
+ *
+ * @ptr: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns nothing.
+ */
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
+{
+	tomoyo_put_group(ptr->group);
+}
+
+/**
+ * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
+ *
+ * @value: Number to check.
+ * @ptr:   Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true if @value matches @ptr, false otherwise.
+ */
+bool tomoyo_compare_number_union(const unsigned long value,
+				 const struct tomoyo_number_union *ptr)
+{
+	if (ptr->group)
+		return tomoyo_number_matches_group(value, value, ptr->group);
+	return value >= ptr->values[0] && value <= ptr->values[1];
+}
+
+/**
+ * tomoyo_add_slash - Add trailing '/' if needed.
+ *
+ * @buf: Pointer to "struct tomoyo_path_info".
+ *
+ * Returns nothing.
+ *
+ * @buf must be generated by tomoyo_encode() because this function does not
+ * allocate memory for adding '/'.
+ */
+static void tomoyo_add_slash(struct tomoyo_path_info *buf)
+{
+	if (buf->is_dir)
+		return;
+	/*
+	 * This is OK because tomoyo_encode() reserves space for appending "/".
+	 */
+	strcat((char *) buf->name, "/");
+	tomoyo_fill_path_info(buf);
+}
+
+/**
+ * tomoyo_get_realpath - Get realpath.
+ *
+ * @buf:  Pointer to "struct tomoyo_path_info".
+ * @path: Pointer to "struct path".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
+{
+	buf->name = tomoyo_realpath_from_path(path);
+	if (buf->name) {
+		tomoyo_fill_path_info(buf);
+		return true;
+	}
+	return false;
+}
+
+/**
+ * tomoyo_audit_path_log - Audit path request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
+{
+	return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
+				 [r->param.path.operation],
+				 r->param.path.filename->name);
+}
+
+/**
+ * tomoyo_audit_path2_log - Audit path/path request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
+{
+	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
+				 [tomoyo_pp2mac[r->param.path2.operation]],
+				 r->param.path2.filename1->name,
+				 r->param.path2.filename2->name);
+}
+
+/**
+ * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
+{
+	return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
+				 tomoyo_mac_keywords
+				 [tomoyo_pnnn2mac[r->param.mkdev.operation]],
+				 r->param.mkdev.filename->name,
+				 r->param.mkdev.mode, r->param.mkdev.major,
+				 r->param.mkdev.minor);
+}
+
+/**
+ * tomoyo_audit_path_number_log - Audit path/number request log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
+{
+	const u8 type = r->param.path_number.operation;
+	u8 radix;
+	char buffer[64];
+	switch (type) {
+	case TOMOYO_TYPE_CREATE:
+	case TOMOYO_TYPE_MKDIR:
+	case TOMOYO_TYPE_MKFIFO:
+	case TOMOYO_TYPE_MKSOCK:
+	case TOMOYO_TYPE_CHMOD:
+		radix = TOMOYO_VALUE_TYPE_OCTAL;
+		break;
+	case TOMOYO_TYPE_IOCTL:
+		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
+		break;
+	default:
+		radix = TOMOYO_VALUE_TYPE_DECIMAL;
+		break;
+	}
+	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
+			   radix);
+	return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
+				 [tomoyo_pn2mac[type]],
+				 r->param.path_number.filename->name, buffer);
+}
+
+/**
+ * tomoyo_check_path_acl - Check permission for path operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ *
+ * To be able to use wildcard for domain transition, this function sets
+ * matching entry on success. Since the caller holds tomoyo_read_lock(),
+ * it is safe to set matching entry.
+ */
+static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
+				  const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
+							 head);
+	if (acl->perm & (1 << r->param.path.operation)) {
+		r->param.path.matched_path =
+			tomoyo_compare_name_union(r->param.path.filename,
+						  &acl->name);
+		return r->param.path.matched_path != NULL;
+	}
+	return false;
+}
+
+/**
+ * tomoyo_check_path_number_acl - Check permission for path number operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
+					 const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_path_number_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return (acl->perm & (1 << r->param.path_number.operation)) &&
+		tomoyo_compare_number_union(r->param.path_number.number,
+					    &acl->number) &&
+		tomoyo_compare_name_union(r->param.path_number.filename,
+					  &acl->name);
+}
+
+/**
+ * tomoyo_check_path2_acl - Check permission for path path operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
+				   const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_path2_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return (acl->perm & (1 << r->param.path2.operation)) &&
+		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
+		&& tomoyo_compare_name_union(r->param.path2.filename2,
+					     &acl->name2);
+}
+
+/**
+ * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
+				   const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_mkdev_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return (acl->perm & (1 << r->param.mkdev.operation)) &&
+		tomoyo_compare_number_union(r->param.mkdev.mode,
+					    &acl->mode) &&
+		tomoyo_compare_number_union(r->param.mkdev.major,
+					    &acl->major) &&
+		tomoyo_compare_number_union(r->param.mkdev.minor,
+					    &acl->minor) &&
+		tomoyo_compare_name_union(r->param.mkdev.filename,
+					  &acl->name);
+}
+
+/**
+ * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
+				 const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_name_union(&p1->name, &p2->name);
+}
+
+/**
+ * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
+				  struct tomoyo_acl_info *b,
+				  const bool is_delete)
+{
+	u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
+		->perm;
+	u16 perm = *a_perm;
+	const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
+ *
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_path_acl(const u16 perm,
+				  struct tomoyo_acl_param *param)
+{
+	struct tomoyo_path_acl e = {
+		.head.type = TOMOYO_TYPE_PATH_ACL,
+		.perm = perm
+	};
+	int error;
+	if (!tomoyo_parse_name_union(param, &e.name))
+		error = -EINVAL;
+	else
+		error = tomoyo_update_domain(&e.head, sizeof(e), param,
+					     tomoyo_same_path_acl,
+					     tomoyo_merge_path_acl);
+	tomoyo_put_name_union(&e.name);
+	return error;
+}
+
+/**
+ * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
+					 const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_name_union(&p1->name, &p2->name) &&
+		tomoyo_same_number_union(&p1->mode, &p2->mode) &&
+		tomoyo_same_number_union(&p1->major, &p2->major) &&
+		tomoyo_same_number_union(&p1->minor, &p2->minor);
+}
+
+/**
+ * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
+				   struct tomoyo_acl_info *b,
+				   const bool is_delete)
+{
+	u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
+					 head)->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
+		->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
+ *
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_mkdev_acl(const u8 perm,
+				   struct tomoyo_acl_param *param)
+{
+	struct tomoyo_mkdev_acl e = {
+		.head.type = TOMOYO_TYPE_MKDEV_ACL,
+		.perm = perm
+	};
+	int error;
+	if (!tomoyo_parse_name_union(param, &e.name) ||
+	    !tomoyo_parse_number_union(param, &e.mode) ||
+	    !tomoyo_parse_number_union(param, &e.major) ||
+	    !tomoyo_parse_number_union(param, &e.minor))
+		error = -EINVAL;
+	else
+		error = tomoyo_update_domain(&e.head, sizeof(e), param,
+					     tomoyo_same_mkdev_acl,
+					     tomoyo_merge_mkdev_acl);
+	tomoyo_put_name_union(&e.name);
+	tomoyo_put_number_union(&e.mode);
+	tomoyo_put_number_union(&e.major);
+	tomoyo_put_number_union(&e.minor);
+	return error;
+}
+
+/**
+ * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
+				  const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
+		tomoyo_same_name_union(&p1->name2, &p2->name2);
+}
+
+/**
+ * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
+				   struct tomoyo_acl_info *b,
+				   const bool is_delete)
+{
+	u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
+		->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
+ *
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_path2_acl(const u8 perm,
+				   struct tomoyo_acl_param *param)
+{
+	struct tomoyo_path2_acl e = {
+		.head.type = TOMOYO_TYPE_PATH2_ACL,
+		.perm = perm
+	};
+	int error;
+	if (!tomoyo_parse_name_union(param, &e.name1) ||
+	    !tomoyo_parse_name_union(param, &e.name2))
+		error = -EINVAL;
+	else
+		error = tomoyo_update_domain(&e.head, sizeof(e), param,
+					     tomoyo_same_path2_acl,
+					     tomoyo_merge_path2_acl);
+	tomoyo_put_name_union(&e.name1);
+	tomoyo_put_name_union(&e.name2);
+	return error;
+}
+
+/**
+ * tomoyo_path_permission - Check permission for single path operation.
+ *
+ * @r:         Pointer to "struct tomoyo_request_info".
+ * @operation: Type of operation.
+ * @filename:  Filename to check.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+				  const struct tomoyo_path_info *filename)
+{
+	int error;
+
+	r->type = tomoyo_p2mac[operation];
+	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
+	if (r->mode == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	r->param_type = TOMOYO_TYPE_PATH_ACL;
+	r->param.path.filename = filename;
+	r->param.path.operation = operation;
+	do {
+		tomoyo_check_acl(r, tomoyo_check_path_acl);
+		error = tomoyo_audit_path_log(r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+	return error;
+}
+
+/**
+ * tomoyo_execute_permission - Check permission for execute operation.
+ *
+ * @r:         Pointer to "struct tomoyo_request_info".
+ * @filename:  Filename to check.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_execute_permission(struct tomoyo_request_info *r,
+			      const struct tomoyo_path_info *filename)
+{
+	/*
+	 * Unlike other permission checks, this check is done regardless of
+	 * profile mode settings in order to check for domain transition
+	 * preference.
+	 */
+	r->type = TOMOYO_MAC_FILE_EXECUTE;
+	r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
+	r->param_type = TOMOYO_TYPE_PATH_ACL;
+	r->param.path.filename = filename;
+	r->param.path.operation = TOMOYO_TYPE_EXECUTE;
+	tomoyo_check_acl(r, tomoyo_check_path_acl);
+	r->ee->transition = r->matched_acl && r->matched_acl->cond ?
+		r->matched_acl->cond->transit : NULL;
+	if (r->mode != TOMOYO_CONFIG_DISABLED)
+		return tomoyo_audit_path_log(r);
+	return 0;
+}
+
+/**
+ * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
+					const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
+							       head);
+	const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
+							       head);
+	return tomoyo_same_name_union(&p1->name, &p2->name) &&
+		tomoyo_same_number_union(&p1->number, &p2->number);
+}
+
+/**
+ * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
+					 struct tomoyo_acl_info *b,
+					 const bool is_delete)
+{
+	u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
+					  head)->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
+		->perm;
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
+ *
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_update_path_number_acl(const u8 perm,
+					 struct tomoyo_acl_param *param)
+{
+	struct tomoyo_path_number_acl e = {
+		.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
+		.perm = perm
+	};
+	int error;
+	if (!tomoyo_parse_name_union(param, &e.name) ||
+	    !tomoyo_parse_number_union(param, &e.number))
+		error = -EINVAL;
+	else
+		error = tomoyo_update_domain(&e.head, sizeof(e), param,
+					     tomoyo_same_path_number_acl,
+					     tomoyo_merge_path_number_acl);
+	tomoyo_put_name_union(&e.name);
+	tomoyo_put_number_union(&e.number);
+	return error;
+}
+
+/**
+ * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
+ *
+ * @type:   Type of operation.
+ * @path:   Pointer to "struct path".
+ * @number: Number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_path_number_perm(const u8 type, struct path *path,
+			    unsigned long number)
+{
+	struct tomoyo_request_info r;
+	struct tomoyo_obj_info obj = {
+		.path1 = *path,
+	};
+	int error = -ENOMEM;
+	struct tomoyo_path_info buf;
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
+	    == TOMOYO_CONFIG_DISABLED || !path->dentry)
+		return 0;
+	idx = tomoyo_read_lock();
+	if (!tomoyo_get_realpath(&buf, path))
+		goto out;
+	r.obj = &obj;
+	if (type == TOMOYO_TYPE_MKDIR)
+		tomoyo_add_slash(&buf);
+	r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
+	r.param.path_number.operation = type;
+	r.param.path_number.filename = &buf;
+	r.param.path_number.number = number;
+	do {
+		tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
+		error = tomoyo_audit_path_number_log(&r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+	kfree(buf.name);
+ out:
+	tomoyo_read_unlock(idx);
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
+		error = 0;
+	return error;
+}
+
+/**
+ * tomoyo_check_open_permission - Check permission for "read" and "write".
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @path:   Pointer to "struct path".
+ * @flag:   Flags for open().
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
+				 struct path *path, const int flag)
+{
+	const u8 acc_mode = ACC_MODE(flag);
+	int error = 0;
+	struct tomoyo_path_info buf;
+	struct tomoyo_request_info r;
+	struct tomoyo_obj_info obj = {
+		.path1 = *path,
+	};
+	int idx;
+
+	buf.name = NULL;
+	r.mode = TOMOYO_CONFIG_DISABLED;
+	idx = tomoyo_read_lock();
+	if (acc_mode &&
+	    tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
+	    != TOMOYO_CONFIG_DISABLED) {
+		if (!tomoyo_get_realpath(&buf, path)) {
+			error = -ENOMEM;
+			goto out;
+		}
+		r.obj = &obj;
+		if (acc_mode & MAY_READ)
+			error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
+						       &buf);
+		if (!error && (acc_mode & MAY_WRITE))
+			error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
+						       TOMOYO_TYPE_APPEND :
+						       TOMOYO_TYPE_WRITE,
+						       &buf);
+	}
+ out:
+	kfree(buf.name);
+	tomoyo_read_unlock(idx);
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
+		error = 0;
+	return error;
+}
+
+/**
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
+ *
+ * @operation: Type of operation.
+ * @path:      Pointer to "struct path".
+ * @target:    Symlink's target if @operation is TOMOYO_TYPE_SYMLINK,
+ *             NULL otherwise.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_path_perm(const u8 operation, struct path *path, const char *target)
+{
+	struct tomoyo_request_info r;
+	struct tomoyo_obj_info obj = {
+		.path1 = *path,
+	};
+	int error;
+	struct tomoyo_path_info buf;
+	bool is_enforce;
+	struct tomoyo_path_info symlink_target;
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
+	    == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
+	error = -ENOMEM;
+	buf.name = NULL;
+	idx = tomoyo_read_lock();
+	if (!tomoyo_get_realpath(&buf, path))
+		goto out;
+	r.obj = &obj;
+	switch (operation) {
+	case TOMOYO_TYPE_RMDIR:
+	case TOMOYO_TYPE_CHROOT:
+		tomoyo_add_slash(&buf);
+		break;
+	case TOMOYO_TYPE_SYMLINK:
+		symlink_target.name = tomoyo_encode(target);
+		if (!symlink_target.name)
+			goto out;
+		tomoyo_fill_path_info(&symlink_target);
+		obj.symlink_target = &symlink_target;
+		break;
+	}
+	error = tomoyo_path_permission(&r, operation, &buf);
+	if (operation == TOMOYO_TYPE_SYMLINK)
+		kfree(symlink_target.name);
+ out:
+	kfree(buf.name);
+	tomoyo_read_unlock(idx);
+	if (!is_enforce)
+		error = 0;
+	return error;
+}
+
+/**
+ * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
+ *
+ * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
+ * @path:      Pointer to "struct path".
+ * @mode:      Create mode.
+ * @dev:       Device number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mkdev_perm(const u8 operation, struct path *path,
+		      const unsigned int mode, unsigned int dev)
+{
+	struct tomoyo_request_info r;
+	struct tomoyo_obj_info obj = {
+		.path1 = *path,
+	};
+	int error = -ENOMEM;
+	struct tomoyo_path_info buf;
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+	    == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	idx = tomoyo_read_lock();
+	error = -ENOMEM;
+	if (tomoyo_get_realpath(&buf, path)) {
+		r.obj = &obj;
+		dev = new_decode_dev(dev);
+		r.param_type = TOMOYO_TYPE_MKDEV_ACL;
+		r.param.mkdev.filename = &buf;
+		r.param.mkdev.operation = operation;
+		r.param.mkdev.mode = mode;
+		r.param.mkdev.major = MAJOR(dev);
+		r.param.mkdev.minor = MINOR(dev);
+		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
+		error = tomoyo_audit_mkdev_log(&r);
+		kfree(buf.name);
+	}
+	tomoyo_read_unlock(idx);
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
+		error = 0;
+	return error;
+}
+
+/**
+ * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
+ *
+ * @operation: Type of operation.
+ * @path1:      Pointer to "struct path".
+ * @path2:      Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_path2_perm(const u8 operation, struct path *path1,
+		      struct path *path2)
+{
+	int error = -ENOMEM;
+	struct tomoyo_path_info buf1;
+	struct tomoyo_path_info buf2;
+	struct tomoyo_request_info r;
+	struct tomoyo_obj_info obj = {
+		.path1 = *path1,
+		.path2 = *path2,
+	};
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+	    == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	buf1.name = NULL;
+	buf2.name = NULL;
+	idx = tomoyo_read_lock();
+	if (!tomoyo_get_realpath(&buf1, path1) ||
+	    !tomoyo_get_realpath(&buf2, path2))
+		goto out;
+	switch (operation) {
+		struct dentry *dentry;
+	case TOMOYO_TYPE_RENAME:
+	case TOMOYO_TYPE_LINK:
+		dentry = path1->dentry;
+		if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+			break;
+		/* fall through */
+	case TOMOYO_TYPE_PIVOT_ROOT:
+		tomoyo_add_slash(&buf1);
+		tomoyo_add_slash(&buf2);
+		break;
+	}
+	r.obj = &obj;
+	r.param_type = TOMOYO_TYPE_PATH2_ACL;
+	r.param.path2.operation = operation;
+	r.param.path2.filename1 = &buf1;
+	r.param.path2.filename2 = &buf2;
+	do {
+		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
+		error = tomoyo_audit_path2_log(&r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+ out:
+	kfree(buf1.name);
+	kfree(buf2.name);
+	tomoyo_read_unlock(idx);
+	if (r.mode != TOMOYO_CONFIG_ENFORCING)
+		error = 0;
+	return error;
+}
+
+/**
+ * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
+				  const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+	return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
+		tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
+		tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
+		tomoyo_same_number_union(&p1->flags, &p2->flags);
+}
+
+/**
+ * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
+{
+	struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+	int error;
+	if (!tomoyo_parse_name_union(param, &e.dev_name) ||
+	    !tomoyo_parse_name_union(param, &e.dir_name) ||
+	    !tomoyo_parse_name_union(param, &e.fs_type) ||
+	    !tomoyo_parse_number_union(param, &e.flags))
+		error = -EINVAL;
+	else
+		error = tomoyo_update_domain(&e.head, sizeof(e), param,
+					     tomoyo_same_mount_acl, NULL);
+	tomoyo_put_name_union(&e.dev_name);
+	tomoyo_put_name_union(&e.dir_name);
+	tomoyo_put_name_union(&e.fs_type);
+	tomoyo_put_number_union(&e.flags);
+	return error;
+}
+
+/**
+ * tomoyo_write_file - Update file related list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_file(struct tomoyo_acl_param *param)
+{
+	u16 perm = 0;
+	u8 type;
+	const char *operation = tomoyo_read_token(param);
+	for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
+		if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
+			perm |= 1 << type;
+	if (perm)
+		return tomoyo_update_path_acl(perm, param);
+	for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
+		if (tomoyo_permstr(operation,
+				   tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
+			perm |= 1 << type;
+	if (perm)
+		return tomoyo_update_path2_acl(perm, param);
+	for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
+		if (tomoyo_permstr(operation,
+				   tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
+			perm |= 1 << type;
+	if (perm)
+		return tomoyo_update_path_number_acl(perm, param);
+	for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
+		if (tomoyo_permstr(operation,
+				   tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
+			perm |= 1 << type;
+	if (perm)
+		return tomoyo_update_mkdev_acl(perm, param);
+	if (tomoyo_permstr(operation,
+			   tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
+		return tomoyo_update_mount_acl(param);
+	return -EINVAL;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/gc.c b/ap/os/linux/linux-3.4.x/security/tomoyo/gc.c
new file mode 100644
index 0000000..986a6a7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/gc.c
@@ -0,0 +1,655 @@
+/*
+ * security/tomoyo/gc.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/kthread.h>
+#include <linux/slab.h>
+
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr:  Pointer to allocated memory.
+ *
+ * Returns nothing.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+static inline void tomoyo_memory_free(void *ptr)
+{
+	tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr);
+	kfree(ptr);
+}
+
+/* The list for "struct tomoyo_io_buffer". */
+static LIST_HEAD(tomoyo_io_buffer_list);
+/* Lock for protecting tomoyo_io_buffer_list. */
+static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
+
+/**
+ * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns true if @element is used by /sys/kernel/security/tomoyo/ users,
+ * false otherwise.
+ */
+static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
+{
+	struct tomoyo_io_buffer *head;
+	bool in_use = false;
+
+	spin_lock(&tomoyo_io_buffer_list_lock);
+	list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
+		head->users++;
+		spin_unlock(&tomoyo_io_buffer_list_lock);
+		mutex_lock(&head->io_sem);
+		if (head->r.domain == element || head->r.group == element ||
+		    head->r.acl == element || &head->w.domain->list == element)
+			in_use = true;
+		mutex_unlock(&head->io_sem);
+		spin_lock(&tomoyo_io_buffer_list_lock);
+		head->users--;
+		if (in_use)
+			break;
+	}
+	spin_unlock(&tomoyo_io_buffer_list_lock);
+	return in_use;
+}
+
+/**
+ * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
+ *
+ * @string: String to check.
+ *
+ * Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
+ * false otherwise.
+ */
+static bool tomoyo_name_used_by_io_buffer(const char *string)
+{
+	struct tomoyo_io_buffer *head;
+	const size_t size = strlen(string) + 1;
+	bool in_use = false;
+
+	spin_lock(&tomoyo_io_buffer_list_lock);
+	list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
+		int i;
+		head->users++;
+		spin_unlock(&tomoyo_io_buffer_list_lock);
+		mutex_lock(&head->io_sem);
+		for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
+			const char *w = head->r.w[i];
+			if (w < string || w > string + size)
+				continue;
+			in_use = true;
+			break;
+		}
+		mutex_unlock(&head->io_sem);
+		spin_lock(&tomoyo_io_buffer_list_lock);
+		head->users--;
+		if (in_use)
+			break;
+	}
+	spin_unlock(&tomoyo_io_buffer_list_lock);
+	return in_use;
+}
+
+/**
+ * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_transition_control(struct list_head *element)
+{
+	struct tomoyo_transition_control *ptr =
+		container_of(element, typeof(*ptr), head.list);
+	tomoyo_put_name(ptr->domainname);
+	tomoyo_put_name(ptr->program);
+}
+
+/**
+ * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_aggregator(struct list_head *element)
+{
+	struct tomoyo_aggregator *ptr =
+		container_of(element, typeof(*ptr), head.list);
+	tomoyo_put_name(ptr->original_name);
+	tomoyo_put_name(ptr->aggregated_name);
+}
+
+/**
+ * tomoyo_del_manager - Delete members in "struct tomoyo_manager".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_manager(struct list_head *element)
+{
+	struct tomoyo_manager *ptr =
+		container_of(element, typeof(*ptr), head.list);
+	tomoyo_put_name(ptr->manager);
+}
+
+/**
+ * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_del_acl(struct list_head *element)
+{
+	struct tomoyo_acl_info *acl =
+		container_of(element, typeof(*acl), list);
+	tomoyo_put_condition(acl->cond);
+	switch (acl->type) {
+	case TOMOYO_TYPE_PATH_ACL:
+		{
+			struct tomoyo_path_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->name);
+		}
+		break;
+	case TOMOYO_TYPE_PATH2_ACL:
+		{
+			struct tomoyo_path2_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->name1);
+			tomoyo_put_name_union(&entry->name2);
+		}
+		break;
+	case TOMOYO_TYPE_PATH_NUMBER_ACL:
+		{
+			struct tomoyo_path_number_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->name);
+			tomoyo_put_number_union(&entry->number);
+		}
+		break;
+	case TOMOYO_TYPE_MKDEV_ACL:
+		{
+			struct tomoyo_mkdev_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->name);
+			tomoyo_put_number_union(&entry->mode);
+			tomoyo_put_number_union(&entry->major);
+			tomoyo_put_number_union(&entry->minor);
+		}
+		break;
+	case TOMOYO_TYPE_MOUNT_ACL:
+		{
+			struct tomoyo_mount_acl *entry
+				= container_of(acl, typeof(*entry), head);
+			tomoyo_put_name_union(&entry->dev_name);
+			tomoyo_put_name_union(&entry->dir_name);
+			tomoyo_put_name_union(&entry->fs_type);
+			tomoyo_put_number_union(&entry->flags);
+		}
+		break;
+	case TOMOYO_TYPE_ENV_ACL:
+		{
+			struct tomoyo_env_acl *entry =
+				container_of(acl, typeof(*entry), head);
+
+			tomoyo_put_name(entry->env);
+		}
+		break;
+	case TOMOYO_TYPE_INET_ACL:
+		{
+			struct tomoyo_inet_acl *entry =
+				container_of(acl, typeof(*entry), head);
+
+			tomoyo_put_group(entry->address.group);
+			tomoyo_put_number_union(&entry->port);
+		}
+		break;
+	case TOMOYO_TYPE_UNIX_ACL:
+		{
+			struct tomoyo_unix_acl *entry =
+				container_of(acl, typeof(*entry), head);
+
+			tomoyo_put_name_union(&entry->name);
+		}
+		break;
+	case TOMOYO_TYPE_MANUAL_TASK_ACL:
+		{
+			struct tomoyo_task_acl *entry =
+				container_of(acl, typeof(*entry), head);
+			tomoyo_put_name(entry->domainname);
+		}
+		break;
+	}
+}
+
+/**
+ * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+static inline void tomoyo_del_domain(struct list_head *element)
+{
+	struct tomoyo_domain_info *domain =
+		container_of(element, typeof(*domain), list);
+	struct tomoyo_acl_info *acl;
+	struct tomoyo_acl_info *tmp;
+	/*
+	 * Since this domain is referenced from neither
+	 * "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
+	 * elements without checking for is_deleted flag.
+	 */
+	list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
+		tomoyo_del_acl(&acl->list);
+		tomoyo_memory_free(acl);
+	}
+	tomoyo_put_name(domain->domainname);
+}
+
+/**
+ * tomoyo_del_condition - Delete members in "struct tomoyo_condition".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+void tomoyo_del_condition(struct list_head *element)
+{
+	struct tomoyo_condition *cond = container_of(element, typeof(*cond),
+						     head.list);
+	const u16 condc = cond->condc;
+	const u16 numbers_count = cond->numbers_count;
+	const u16 names_count = cond->names_count;
+	const u16 argc = cond->argc;
+	const u16 envc = cond->envc;
+	unsigned int i;
+	const struct tomoyo_condition_element *condp
+		= (const struct tomoyo_condition_element *) (cond + 1);
+	struct tomoyo_number_union *numbers_p
+		= (struct tomoyo_number_union *) (condp + condc);
+	struct tomoyo_name_union *names_p
+		= (struct tomoyo_name_union *) (numbers_p + numbers_count);
+	const struct tomoyo_argv *argv
+		= (const struct tomoyo_argv *) (names_p + names_count);
+	const struct tomoyo_envp *envp
+		= (const struct tomoyo_envp *) (argv + argc);
+	for (i = 0; i < numbers_count; i++)
+		tomoyo_put_number_union(numbers_p++);
+	for (i = 0; i < names_count; i++)
+		tomoyo_put_name_union(names_p++);
+	for (i = 0; i < argc; argv++, i++)
+		tomoyo_put_name(argv->value);
+	for (i = 0; i < envc; envp++, i++) {
+		tomoyo_put_name(envp->name);
+		tomoyo_put_name(envp->value);
+	}
+}
+
+/**
+ * tomoyo_del_name - Delete members in "struct tomoyo_name".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_name(struct list_head *element)
+{
+	/* Nothing to do. */
+}
+
+/**
+ * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_path_group(struct list_head *element)
+{
+	struct tomoyo_path_group *member =
+		container_of(element, typeof(*member), head.list);
+	tomoyo_put_name(member->member_name);
+}
+
+/**
+ * tomoyo_del_group - Delete "struct tomoyo_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_group(struct list_head *element)
+{
+	struct tomoyo_group *group =
+		container_of(element, typeof(*group), head.list);
+	tomoyo_put_name(group->group_name);
+}
+
+/**
+ * tomoyo_del_address_group - Delete members in "struct tomoyo_address_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_address_group(struct list_head *element)
+{
+	/* Nothing to do. */
+}
+
+/**
+ * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_del_number_group(struct list_head *element)
+{
+	/* Nothing to do. */
+}
+
+/**
+ * tomoyo_try_to_gc - Try to kfree() an entry.
+ *
+ * @type:    One of values in "enum tomoyo_policy_id".
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+static void tomoyo_try_to_gc(const enum tomoyo_policy_id type,
+			     struct list_head *element)
+{
+	/*
+	 * __list_del_entry() guarantees that the list element became no longer
+	 * reachable from the list which the element was originally on (e.g.
+	 * tomoyo_domain_list). Also, synchronize_srcu() guarantees that the
+	 * list element became no longer referenced by syscall users.
+	 */
+	__list_del_entry(element);
+	mutex_unlock(&tomoyo_policy_lock);
+	synchronize_srcu(&tomoyo_ss);
+	/*
+	 * However, there are two users which may still be using the list
+	 * element. We need to defer until both users forget this element.
+	 *
+	 * Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl}
+	 * and "struct tomoyo_io_buffer"->w.domain forget this element.
+	 */
+	if (tomoyo_struct_used_by_io_buffer(element))
+		goto reinject;
+	switch (type) {
+	case TOMOYO_ID_TRANSITION_CONTROL:
+		tomoyo_del_transition_control(element);
+		break;
+	case TOMOYO_ID_MANAGER:
+		tomoyo_del_manager(element);
+		break;
+	case TOMOYO_ID_AGGREGATOR:
+		tomoyo_del_aggregator(element);
+		break;
+	case TOMOYO_ID_GROUP:
+		tomoyo_del_group(element);
+		break;
+	case TOMOYO_ID_PATH_GROUP:
+		tomoyo_del_path_group(element);
+		break;
+	case TOMOYO_ID_ADDRESS_GROUP:
+		tomoyo_del_address_group(element);
+		break;
+	case TOMOYO_ID_NUMBER_GROUP:
+		tomoyo_del_number_group(element);
+		break;
+	case TOMOYO_ID_CONDITION:
+		tomoyo_del_condition(element);
+		break;
+	case TOMOYO_ID_NAME:
+		/*
+		 * Don't kfree() until all "struct tomoyo_io_buffer"->r.w[]
+		 * forget this element.
+		 */
+		if (tomoyo_name_used_by_io_buffer
+		    (container_of(element, typeof(struct tomoyo_name),
+				  head.list)->entry.name))
+			goto reinject;
+		tomoyo_del_name(element);
+		break;
+	case TOMOYO_ID_ACL:
+		tomoyo_del_acl(element);
+		break;
+	case TOMOYO_ID_DOMAIN:
+		/*
+		 * Don't kfree() until all "struct cred"->security forget this
+		 * element.
+		 */
+		if (atomic_read(&container_of
+				(element, typeof(struct tomoyo_domain_info),
+				 list)->users))
+			goto reinject;
+		break;
+	case TOMOYO_MAX_POLICY:
+		break;
+	}
+	mutex_lock(&tomoyo_policy_lock);
+	if (type == TOMOYO_ID_DOMAIN)
+		tomoyo_del_domain(element);
+	tomoyo_memory_free(element);
+	return;
+reinject:
+	/*
+	 * We can safely reinject this element here bacause
+	 * (1) Appending list elements and removing list elements are protected
+	 *     by tomoyo_policy_lock mutex.
+	 * (2) Only this function removes list elements and this function is
+	 *     exclusively executed by tomoyo_gc_mutex mutex.
+	 * are true.
+	 */
+	mutex_lock(&tomoyo_policy_lock);
+	list_add_rcu(element, element->prev);
+}
+
+/**
+ * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head".
+ *
+ * @id:          One of values in "enum tomoyo_policy_id".
+ * @member_list: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_collect_member(const enum tomoyo_policy_id id,
+				  struct list_head *member_list)
+{
+	struct tomoyo_acl_head *member;
+	struct tomoyo_acl_head *tmp;
+	list_for_each_entry_safe(member, tmp, member_list, list) {
+		if (!member->is_deleted)
+			continue;
+		member->is_deleted = TOMOYO_GC_IN_PROGRESS;
+		tomoyo_try_to_gc(id, &member->list);
+	}
+}
+
+/**
+ * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
+ *
+ * @list: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_collect_acl(struct list_head *list)
+{
+	struct tomoyo_acl_info *acl;
+	struct tomoyo_acl_info *tmp;
+	list_for_each_entry_safe(acl, tmp, list, list) {
+		if (!acl->is_deleted)
+			continue;
+		acl->is_deleted = TOMOYO_GC_IN_PROGRESS;
+		tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);
+	}
+}
+
+/**
+ * tomoyo_collect_entry - Try to kfree() deleted elements.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_collect_entry(void)
+{
+	int i;
+	enum tomoyo_policy_id id;
+	struct tomoyo_policy_namespace *ns;
+	mutex_lock(&tomoyo_policy_lock);
+	{
+		struct tomoyo_domain_info *domain;
+		struct tomoyo_domain_info *tmp;
+		list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
+					 list) {
+			tomoyo_collect_acl(&domain->acl_info_list);
+			if (!domain->is_deleted || atomic_read(&domain->users))
+				continue;
+			tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);
+		}
+	}
+	list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
+		for (id = 0; id < TOMOYO_MAX_POLICY; id++)
+			tomoyo_collect_member(id, &ns->policy_list[id]);
+		for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
+			tomoyo_collect_acl(&ns->acl_group[i]);
+	}
+	{
+		struct tomoyo_shared_acl_head *ptr;
+		struct tomoyo_shared_acl_head *tmp;
+		list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list,
+					 list) {
+			if (atomic_read(&ptr->users) > 0)
+				continue;
+			atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
+			tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list);
+		}
+	}
+	list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
+		for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
+			struct list_head *list = &ns->group_list[i];
+			struct tomoyo_group *group;
+			struct tomoyo_group *tmp;
+			switch (i) {
+			case 0:
+				id = TOMOYO_ID_PATH_GROUP;
+				break;
+			case 1:
+				id = TOMOYO_ID_NUMBER_GROUP;
+				break;
+			default:
+				id = TOMOYO_ID_ADDRESS_GROUP;
+				break;
+			}
+			list_for_each_entry_safe(group, tmp, list, head.list) {
+				tomoyo_collect_member(id, &group->member_list);
+				if (!list_empty(&group->member_list) ||
+				    atomic_read(&group->head.users) > 0)
+					continue;
+				atomic_set(&group->head.users,
+					   TOMOYO_GC_IN_PROGRESS);
+				tomoyo_try_to_gc(TOMOYO_ID_GROUP,
+						 &group->head.list);
+			}
+		}
+	}
+	for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+		struct list_head *list = &tomoyo_name_list[i];
+		struct tomoyo_shared_acl_head *ptr;
+		struct tomoyo_shared_acl_head *tmp;
+		list_for_each_entry_safe(ptr, tmp, list, list) {
+			if (atomic_read(&ptr->users) > 0)
+				continue;
+			atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
+			tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+}
+
+/**
+ * tomoyo_gc_thread - Garbage collector thread function.
+ *
+ * @unused: Unused.
+ *
+ * Returns 0.
+ */
+static int tomoyo_gc_thread(void *unused)
+{
+	/* Garbage collector thread is exclusive. */
+	static DEFINE_MUTEX(tomoyo_gc_mutex);
+	if (!mutex_trylock(&tomoyo_gc_mutex))
+		goto out;
+	tomoyo_collect_entry();
+	{
+		struct tomoyo_io_buffer *head;
+		struct tomoyo_io_buffer *tmp;
+
+		spin_lock(&tomoyo_io_buffer_list_lock);
+		list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list,
+					 list) {
+			if (head->users)
+				continue;
+			list_del(&head->list);
+			kfree(head->read_buf);
+			kfree(head->write_buf);
+			kfree(head);
+		}
+		spin_unlock(&tomoyo_io_buffer_list_lock);
+	}
+	mutex_unlock(&tomoyo_gc_mutex);
+out:
+	/* This acts as do_exit(0). */
+	return 0;
+}
+
+/**
+ * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users.
+ *
+ * @head:        Pointer to "struct tomoyo_io_buffer".
+ * @is_register: True if register, false if unregister.
+ *
+ * Returns nothing.
+ */
+void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register)
+{
+	bool is_write = false;
+
+	spin_lock(&tomoyo_io_buffer_list_lock);
+	if (is_register) {
+		head->users = 1;
+		list_add(&head->list, &tomoyo_io_buffer_list);
+	} else {
+		is_write = head->write_buf != NULL;
+		if (!--head->users) {
+			list_del(&head->list);
+			kfree(head->read_buf);
+			kfree(head->write_buf);
+			kfree(head);
+		}
+	}
+	spin_unlock(&tomoyo_io_buffer_list_lock);
+	if (is_write) {
+		struct task_struct *task = kthread_create(tomoyo_gc_thread,
+							  NULL,
+							  "GC for TOMOYO");
+		if (!IS_ERR(task))
+			wake_up_process(task);
+	}
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/group.c b/ap/os/linux/linux-3.4.x/security/tomoyo/group.c
new file mode 100644
index 0000000..5009253
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/group.c
@@ -0,0 +1,198 @@
+/*
+ * security/tomoyo/group.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/**
+ * tomoyo_same_path_group - Check for duplicated "struct tomoyo_path_group" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a,
+				   const struct tomoyo_acl_head *b)
+{
+	return container_of(a, struct tomoyo_path_group, head)->member_name ==
+		container_of(b, struct tomoyo_path_group, head)->member_name;
+}
+
+/**
+ * tomoyo_same_number_group - Check for duplicated "struct tomoyo_number_group" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
+				     const struct tomoyo_acl_head *b)
+{
+	return !memcmp(&container_of(a, struct tomoyo_number_group, head)
+		       ->number,
+		       &container_of(b, struct tomoyo_number_group, head)
+		       ->number,
+		       sizeof(container_of(a, struct tomoyo_number_group, head)
+			      ->number));
+}
+
+/**
+ * tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_address_group(const struct tomoyo_acl_head *a,
+				      const struct tomoyo_acl_head *b)
+{
+	const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1),
+							     head);
+	const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2),
+							     head);
+
+	return tomoyo_same_ipaddr_union(&p1->address, &p2->address);
+}
+
+/**
+ * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @type:  Type of this group.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
+{
+	struct tomoyo_group *group = tomoyo_get_group(param, type);
+	int error = -EINVAL;
+	if (!group)
+		return -ENOMEM;
+	param->list = &group->member_list;
+	if (type == TOMOYO_PATH_GROUP) {
+		struct tomoyo_path_group e = { };
+		e.member_name = tomoyo_get_name(tomoyo_read_token(param));
+		if (!e.member_name) {
+			error = -ENOMEM;
+			goto out;
+		}
+		error = tomoyo_update_policy(&e.head, sizeof(e), param,
+					  tomoyo_same_path_group);
+		tomoyo_put_name(e.member_name);
+	} else if (type == TOMOYO_NUMBER_GROUP) {
+		struct tomoyo_number_group e = { };
+		if (param->data[0] == '@' ||
+		    !tomoyo_parse_number_union(param, &e.number))
+			goto out;
+		error = tomoyo_update_policy(&e.head, sizeof(e), param,
+					  tomoyo_same_number_group);
+		/*
+		 * tomoyo_put_number_union() is not needed because
+		 * param->data[0] != '@'.
+		 */
+	} else {
+		struct tomoyo_address_group e = { };
+
+		if (param->data[0] == '@' ||
+		    !tomoyo_parse_ipaddr_union(param, &e.address))
+			goto out;
+		error = tomoyo_update_policy(&e.head, sizeof(e), param,
+					     tomoyo_same_address_group);
+	}
+out:
+	tomoyo_put_group(group);
+	return error;
+}
+
+/**
+ * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
+ *
+ * @pathname: The name of pathname.
+ * @group:    Pointer to "struct tomoyo_path_group".
+ *
+ * Returns matched member's pathname if @pathname matches pathnames in @group,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+const struct tomoyo_path_info *
+tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
+			  const struct tomoyo_group *group)
+{
+	struct tomoyo_path_group *member;
+	list_for_each_entry_rcu(member, &group->member_list, head.list) {
+		if (member->head.is_deleted)
+			continue;
+		if (!tomoyo_path_matches_pattern(pathname, member->member_name))
+			continue;
+		return member->member_name;
+	}
+	return NULL;
+}
+
+/**
+ * tomoyo_number_matches_group - Check whether the given number matches members of the given number group.
+ *
+ * @min:   Min number.
+ * @max:   Max number.
+ * @group: Pointer to "struct tomoyo_number_group".
+ *
+ * Returns true if @min and @max partially overlaps @group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_number_matches_group(const unsigned long min,
+				 const unsigned long max,
+				 const struct tomoyo_group *group)
+{
+	struct tomoyo_number_group *member;
+	bool matched = false;
+	list_for_each_entry_rcu(member, &group->member_list, head.list) {
+		if (member->head.is_deleted)
+			continue;
+		if (min > member->number.values[1] ||
+		    max < member->number.values[0])
+			continue;
+		matched = true;
+		break;
+	}
+	return matched;
+}
+
+/**
+ * tomoyo_address_matches_group - Check whether the given address matches members of the given address group.
+ *
+ * @is_ipv6: True if @address is an IPv6 address.
+ * @address: An IPv4 or IPv6 address.
+ * @group:   Pointer to "struct tomoyo_address_group".
+ *
+ * Returns true if @address matches addresses in @group group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
+				  const struct tomoyo_group *group)
+{
+	struct tomoyo_address_group *member;
+	bool matched = false;
+	const u8 size = is_ipv6 ? 16 : 4;
+
+	list_for_each_entry_rcu(member, &group->member_list, head.list) {
+		if (member->head.is_deleted)
+			continue;
+		if (member->address.is_ipv6 != is_ipv6)
+			continue;
+		if (memcmp(&member->address.ip[0], address, size) > 0 ||
+		    memcmp(address, &member->address.ip[1], size) > 0)
+			continue;
+		matched = true;
+		break;
+	}
+	return matched;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/load_policy.c b/ap/os/linux/linux-3.4.x/security/tomoyo/load_policy.c
new file mode 100644
index 0000000..078fac0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/load_policy.c
@@ -0,0 +1,109 @@
+/*
+ * security/tomoyo/load_policy.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+
+/*
+ * Path to the policy loader. (default = CONFIG_SECURITY_TOMOYO_POLICY_LOADER)
+ */
+static const char *tomoyo_loader;
+
+/**
+ * tomoyo_loader_setup - Set policy loader.
+ *
+ * @str: Program to use as a policy loader (e.g. /sbin/tomoyo-init ).
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_loader_setup(char *str)
+{
+	tomoyo_loader = str;
+	return 0;
+}
+
+__setup("TOMOYO_loader=", tomoyo_loader_setup);
+
+/**
+ * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ *
+ * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ */
+static bool tomoyo_policy_loader_exists(void)
+{
+	struct path path;
+	if (!tomoyo_loader)
+		tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER;
+	if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
+		printk(KERN_INFO "Not activating Mandatory Access Control "
+		       "as %s does not exist.\n", tomoyo_loader);
+		return false;
+	}
+	path_put(&path);
+	return true;
+}
+
+/*
+ * Path to the trigger. (default = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER)
+ */
+static const char *tomoyo_trigger;
+
+/**
+ * tomoyo_trigger_setup - Set trigger for activation.
+ *
+ * @str: Program to use as an activation trigger (e.g. /sbin/init ).
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_trigger_setup(char *str)
+{
+	tomoyo_trigger = str;
+	return 0;
+}
+
+__setup("TOMOYO_trigger=", tomoyo_trigger_setup);
+
+/**
+ * tomoyo_load_policy - Run external policy loader to load policy.
+ *
+ * @filename: The program about to start.
+ *
+ * This function checks whether @filename is /sbin/init , and if so
+ * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
+ * and then continues invocation of /sbin/init.
+ * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
+ * writes to /sys/kernel/security/tomoyo/ interfaces.
+ *
+ * Returns nothing.
+ */
+void tomoyo_load_policy(const char *filename)
+{
+	static bool done;
+	char *argv[2];
+	char *envp[3];
+
+	if (tomoyo_policy_loaded || done)
+		return;
+	if (!tomoyo_trigger)
+		tomoyo_trigger = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER;
+	if (strcmp(filename, tomoyo_trigger))
+		return;
+	if (!tomoyo_policy_loader_exists())
+		return;
+	done = true;
+	printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
+	       tomoyo_loader);
+	argv[0] = (char *) tomoyo_loader;
+	argv[1] = NULL;
+	envp[0] = "HOME=/";
+	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[2] = NULL;
+	call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+	tomoyo_check_profile();
+}
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/memory.c b/ap/os/linux/linux-3.4.x/security/tomoyo/memory.c
new file mode 100644
index 0000000..0e99571
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/memory.c
@@ -0,0 +1,201 @@
+/*
+ * security/tomoyo/memory.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/hash.h>
+#include <linux/slab.h>
+#include "common.h"
+
+/**
+ * tomoyo_warn_oom - Print out of memory warning message.
+ *
+ * @function: Function's name.
+ */
+void tomoyo_warn_oom(const char *function)
+{
+	/* Reduce error messages. */
+	static pid_t tomoyo_last_pid;
+	const pid_t pid = current->pid;
+	if (tomoyo_last_pid != pid) {
+		printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
+		       function);
+		tomoyo_last_pid = pid;
+	}
+	if (!tomoyo_policy_loaded)
+		panic("MAC Initialization failed.\n");
+}
+
+/* Memoy currently used by policy/audit log/query. */
+unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+/* Memory quota for "policy"/"audit log"/"query". */
+unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
+
+/**
+ * tomoyo_memory_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+bool tomoyo_memory_ok(void *ptr)
+{
+	if (ptr) {
+		const size_t s = ksize(ptr);
+		tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s;
+		if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
+		    tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
+		    tomoyo_memory_quota[TOMOYO_MEMORY_POLICY])
+			return true;
+		tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
+	}
+	tomoyo_warn_oom(__func__);
+	return false;
+}
+
+/**
+ * tomoyo_commit_ok - Check memory quota.
+ *
+ * @data:   Data to copy from.
+ * @size:   Size in byte.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ * @data is zero-cleared on success.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ */
+void *tomoyo_commit_ok(void *data, const unsigned int size)
+{
+	void *ptr = kzalloc(size, GFP_NOFS);
+	if (tomoyo_memory_ok(ptr)) {
+		memmove(ptr, data, size);
+		memset(data, 0, size);
+		return ptr;
+	}
+	kfree(ptr);
+	return NULL;
+}
+
+/**
+ * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @idx:   Index number.
+ *
+ * Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
+ */
+struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
+				      const u8 idx)
+{
+	struct tomoyo_group e = { };
+	struct tomoyo_group *group = NULL;
+	struct list_head *list;
+	const char *group_name = tomoyo_read_token(param);
+	bool found = false;
+	if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
+		return NULL;
+	e.group_name = tomoyo_get_name(group_name);
+	if (!e.group_name)
+		return NULL;
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		goto out;
+	list = &param->ns->group_list[idx];
+	list_for_each_entry(group, list, head.list) {
+		if (e.group_name != group->group_name ||
+		    atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS)
+			continue;
+		atomic_inc(&group->head.users);
+		found = true;
+		break;
+	}
+	if (!found) {
+		struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
+		if (entry) {
+			INIT_LIST_HEAD(&entry->member_list);
+			atomic_set(&entry->head.users, 1);
+			list_add_tail_rcu(&entry->head.list, list);
+			group = entry;
+			found = true;
+		}
+	}
+	mutex_unlock(&tomoyo_policy_lock);
+out:
+	tomoyo_put_name(e.group_name);
+	return found ? group : NULL;
+}
+
+/*
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
+ */
+struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+
+/**
+ * tomoyo_get_name - Allocate permanent memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
+{
+	struct tomoyo_name *ptr;
+	unsigned int hash;
+	int len;
+	struct list_head *head;
+
+	if (!name)
+		return NULL;
+	len = strlen(name) + 1;
+	hash = full_name_hash((const unsigned char *) name, len - 1);
+	head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
+	if (mutex_lock_interruptible(&tomoyo_policy_lock))
+		return NULL;
+	list_for_each_entry(ptr, head, head.list) {
+		if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
+		    atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
+			continue;
+		atomic_inc(&ptr->head.users);
+		goto out;
+	}
+	ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
+	if (tomoyo_memory_ok(ptr)) {
+		ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+		memmove((char *) ptr->entry.name, name, len);
+		atomic_set(&ptr->head.users, 1);
+		tomoyo_fill_path_info(&ptr->entry);
+		list_add_tail(&ptr->head.list, head);
+	} else {
+		kfree(ptr);
+		ptr = NULL;
+	}
+out:
+	mutex_unlock(&tomoyo_policy_lock);
+	return ptr ? &ptr->entry : NULL;
+}
+
+/* Initial namespace.*/
+struct tomoyo_policy_namespace tomoyo_kernel_namespace;
+
+/**
+ * tomoyo_mm_init - Initialize mm related code.
+ */
+void __init tomoyo_mm_init(void)
+{
+	int idx;
+	for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
+		INIT_LIST_HEAD(&tomoyo_name_list[idx]);
+	tomoyo_kernel_namespace.name = "<kernel>";
+	tomoyo_init_policy_namespace(&tomoyo_kernel_namespace);
+	tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace;
+	INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+	tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>");
+	list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/mount.c b/ap/os/linux/linux-3.4.x/security/tomoyo/mount.c
new file mode 100644
index 0000000..fe00cdf
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/mount.c
@@ -0,0 +1,235 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* String table for special mount operations. */
+static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = {
+	[TOMOYO_MOUNT_BIND]            = "--bind",
+	[TOMOYO_MOUNT_MOVE]            = "--move",
+	[TOMOYO_MOUNT_REMOUNT]         = "--remount",
+	[TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
+	[TOMOYO_MOUNT_MAKE_PRIVATE]    = "--make-private",
+	[TOMOYO_MOUNT_MAKE_SLAVE]      = "--make-slave",
+	[TOMOYO_MOUNT_MAKE_SHARED]     = "--make-shared",
+};
+
+/**
+ * tomoyo_audit_mount_log - Audit mount log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
+{
+	return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n",
+				 r->param.mount.dev->name,
+				 r->param.mount.dir->name,
+				 r->param.mount.type->name,
+				 r->param.mount.flags);
+}
+
+/**
+ * tomoyo_check_mount_acl - Check permission for path path path number operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
+				   const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_mount_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	return tomoyo_compare_number_union(r->param.mount.flags,
+					   &acl->flags) &&
+		tomoyo_compare_name_union(r->param.mount.type,
+					  &acl->fs_type) &&
+		tomoyo_compare_name_union(r->param.mount.dir,
+					  &acl->dir_name) &&
+		(!r->param.mount.need_dev ||
+		 tomoyo_compare_name_union(r->param.mount.dev,
+					   &acl->dev_name));
+}
+
+/**
+ * tomoyo_mount_acl - Check permission for mount() operation.
+ *
+ * @r:        Pointer to "struct tomoyo_request_info".
+ * @dev_name: Name of device file. Maybe NULL.
+ * @dir:      Pointer to "struct path".
+ * @type:     Name of filesystem type.
+ * @flags:    Mount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
+			    struct path *dir, const char *type,
+			    unsigned long flags)
+{
+	struct tomoyo_obj_info obj = { };
+	struct path path;
+	struct file_system_type *fstype = NULL;
+	const char *requested_type = NULL;
+	const char *requested_dir_name = NULL;
+	const char *requested_dev_name = NULL;
+	struct tomoyo_path_info rtype;
+	struct tomoyo_path_info rdev;
+	struct tomoyo_path_info rdir;
+	int need_dev = 0;
+	int error = -ENOMEM;
+	r->obj = &obj;
+
+	/* Get fstype. */
+	requested_type = tomoyo_encode(type);
+	if (!requested_type)
+		goto out;
+	rtype.name = requested_type;
+	tomoyo_fill_path_info(&rtype);
+
+	/* Get mount point. */
+	obj.path2 = *dir;
+	requested_dir_name = tomoyo_realpath_from_path(dir);
+	if (!requested_dir_name) {
+		error = -ENOMEM;
+		goto out;
+	}
+	rdir.name = requested_dir_name;
+	tomoyo_fill_path_info(&rdir);
+
+	/* Compare fs name. */
+	if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) {
+		/* dev_name is ignored. */
+	} else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] ||
+		   type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] ||
+		   type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] ||
+		   type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) {
+		/* dev_name is ignored. */
+	} else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] ||
+		   type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) {
+		need_dev = -1; /* dev_name is a directory */
+	} else {
+		fstype = get_fs_type(type);
+		if (!fstype) {
+			error = -ENODEV;
+			goto out;
+		}
+		if (fstype->fs_flags & FS_REQUIRES_DEV)
+			/* dev_name is a block device file. */
+			need_dev = 1;
+	}
+	if (need_dev) {
+		/* Get mount point or device file. */
+		if (!dev_name || kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
+			error = -ENOENT;
+			goto out;
+		}
+		obj.path1 = path;
+		requested_dev_name = tomoyo_realpath_from_path(&path);
+		if (!requested_dev_name) {
+			error = -ENOENT;
+			goto out;
+		}
+	} else {
+		/* Map dev_name to "<NULL>" if no dev_name given. */
+		if (!dev_name)
+			dev_name = "<NULL>";
+		requested_dev_name = tomoyo_encode(dev_name);
+		if (!requested_dev_name) {
+			error = -ENOMEM;
+			goto out;
+		}
+	}
+	rdev.name = requested_dev_name;
+	tomoyo_fill_path_info(&rdev);
+	r->param_type = TOMOYO_TYPE_MOUNT_ACL;
+	r->param.mount.need_dev = need_dev;
+	r->param.mount.dev = &rdev;
+	r->param.mount.dir = &rdir;
+	r->param.mount.type = &rtype;
+	r->param.mount.flags = flags;
+	do {
+		tomoyo_check_acl(r, tomoyo_check_mount_acl);
+		error = tomoyo_audit_mount_log(r);
+	} while (error == TOMOYO_RETRY_REQUEST);
+ out:
+	kfree(requested_dev_name);
+	kfree(requested_dir_name);
+	if (fstype)
+		put_filesystem(fstype);
+	kfree(requested_type);
+	/* Drop refcount obtained by kern_path(). */
+	if (obj.path1.dentry)
+		path_put(&obj.path1);
+	return error;
+}
+
+/**
+ * tomoyo_mount_permission - Check permission for mount() operation.
+ *
+ * @dev_name:  Name of device file. Maybe NULL.
+ * @path:      Pointer to "struct path".
+ * @type:      Name of filesystem type. Maybe NULL.
+ * @flags:     Mount options.
+ * @data_page: Optional data. Maybe NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mount_permission(char *dev_name, struct path *path,
+			    const char *type, unsigned long flags,
+			    void *data_page)
+{
+	struct tomoyo_request_info r;
+	int error;
+	int idx;
+
+	if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+	    == TOMOYO_CONFIG_DISABLED)
+		return 0;
+	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+		flags &= ~MS_MGC_MSK;
+	if (flags & MS_REMOUNT) {
+		type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT];
+		flags &= ~MS_REMOUNT;
+	} else if (flags & MS_BIND) {
+		type = tomoyo_mounts[TOMOYO_MOUNT_BIND];
+		flags &= ~MS_BIND;
+	} else if (flags & MS_SHARED) {
+		if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
+			return -EINVAL;
+		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
+		flags &= ~MS_SHARED;
+	} else if (flags & MS_PRIVATE) {
+		if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE))
+			return -EINVAL;
+		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE];
+		flags &= ~MS_PRIVATE;
+	} else if (flags & MS_SLAVE) {
+		if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE))
+			return -EINVAL;
+		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE];
+		flags &= ~MS_SLAVE;
+	} else if (flags & MS_UNBINDABLE) {
+		if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE))
+			return -EINVAL;
+		type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
+		flags &= ~MS_UNBINDABLE;
+	} else if (flags & MS_MOVE) {
+		type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
+		flags &= ~MS_MOVE;
+	}
+	if (!type)
+		type = "<NULL>";
+	idx = tomoyo_read_lock();
+	error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
+	tomoyo_read_unlock(idx);
+	return error;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/network.c b/ap/os/linux/linux-3.4.x/security/tomoyo/network.c
new file mode 100644
index 0000000..9752771
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/network.c
@@ -0,0 +1,771 @@
+/*
+ * security/tomoyo/network.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/* Structure for holding inet domain socket's address. */
+struct tomoyo_inet_addr_info {
+	__be16 port;           /* In network byte order. */
+	const __be32 *address; /* In network byte order. */
+	bool is_ipv6;
+};
+
+/* Structure for holding unix domain socket's address. */
+struct tomoyo_unix_addr_info {
+	u8 *addr; /* This may not be '\0' terminated string. */
+	unsigned int addr_len;
+};
+
+/* Structure for holding socket address. */
+struct tomoyo_addr_info {
+	u8 protocol;
+	u8 operation;
+	struct tomoyo_inet_addr_info inet;
+	struct tomoyo_unix_addr_info unix0;
+};
+
+/* String table for socket's protocols. */
+const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX] = {
+	[SOCK_STREAM]    = "stream",
+	[SOCK_DGRAM]     = "dgram",
+	[SOCK_RAW]       = "raw",
+	[SOCK_SEQPACKET] = "seqpacket",
+	[0] = " ", /* Dummy for avoiding NULL pointer dereference. */
+	[4] = " ", /* Dummy for avoiding NULL pointer dereference. */
+};
+
+/**
+ * tomoyo_parse_ipaddr_union - Parse an IP address.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_ipaddr_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param,
+			       struct tomoyo_ipaddr_union *ptr)
+{
+	u8 * const min = ptr->ip[0].in6_u.u6_addr8;
+	u8 * const max = ptr->ip[1].in6_u.u6_addr8;
+	char *address = tomoyo_read_token(param);
+	const char *end;
+
+	if (!strchr(address, ':') &&
+	    in4_pton(address, -1, min, '-', &end) > 0) {
+		ptr->is_ipv6 = false;
+		if (!*end)
+			ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
+		else if (*end++ != '-' ||
+			 in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
+			return false;
+		return true;
+	}
+	if (in6_pton(address, -1, min, '-', &end) > 0) {
+		ptr->is_ipv6 = true;
+		if (!*end)
+			memmove(max, min, sizeof(u16) * 8);
+		else if (*end++ != '-' ||
+			 in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
+			return false;
+		return true;
+	}
+	return false;
+}
+
+/**
+ * tomoyo_print_ipv4 - Print an IPv4 address.
+ *
+ * @buffer:     Buffer to write to.
+ * @buffer_len: Size of @buffer.
+ * @min_ip:     Pointer to __be32.
+ * @max_ip:     Pointer to __be32.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_ipv4(char *buffer, const unsigned int buffer_len,
+			      const __be32 *min_ip, const __be32 *max_ip)
+{
+	snprintf(buffer, buffer_len, "%pI4%c%pI4", min_ip,
+		 *min_ip == *max_ip ? '\0' : '-', max_ip);
+}
+
+/**
+ * tomoyo_print_ipv6 - Print an IPv6 address.
+ *
+ * @buffer:     Buffer to write to.
+ * @buffer_len: Size of @buffer.
+ * @min_ip:     Pointer to "struct in6_addr".
+ * @max_ip:     Pointer to "struct in6_addr".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_ipv6(char *buffer, const unsigned int buffer_len,
+			      const struct in6_addr *min_ip,
+			      const struct in6_addr *max_ip)
+{
+	snprintf(buffer, buffer_len, "%pI6c%c%pI6c", min_ip,
+		 !memcmp(min_ip, max_ip, 16) ? '\0' : '-', max_ip);
+}
+
+/**
+ * tomoyo_print_ip - Print an IP address.
+ *
+ * @buf:  Buffer to write to.
+ * @size: Size of @buf.
+ * @ptr:  Pointer to "struct ipaddr_union".
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ip(char *buf, const unsigned int size,
+		     const struct tomoyo_ipaddr_union *ptr)
+{
+	if (ptr->is_ipv6)
+		tomoyo_print_ipv6(buf, size, &ptr->ip[0], &ptr->ip[1]);
+	else
+		tomoyo_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0],
+				  &ptr->ip[1].s6_addr32[0]);
+}
+
+/*
+ * Mapping table from "enum tomoyo_network_acl_index" to
+ * "enum tomoyo_mac_index" for inet domain socket.
+ */
+static const u8 tomoyo_inet2mac
+[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = {
+	[SOCK_STREAM] = {
+		[TOMOYO_NETWORK_BIND]    = TOMOYO_MAC_NETWORK_INET_STREAM_BIND,
+		[TOMOYO_NETWORK_LISTEN]  =
+		TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN,
+		[TOMOYO_NETWORK_CONNECT] =
+		TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT,
+	},
+	[SOCK_DGRAM] = {
+		[TOMOYO_NETWORK_BIND]    = TOMOYO_MAC_NETWORK_INET_DGRAM_BIND,
+		[TOMOYO_NETWORK_SEND]    = TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
+	},
+	[SOCK_RAW]    = {
+		[TOMOYO_NETWORK_BIND]    = TOMOYO_MAC_NETWORK_INET_RAW_BIND,
+		[TOMOYO_NETWORK_SEND]    = TOMOYO_MAC_NETWORK_INET_RAW_SEND,
+	},
+};
+
+/*
+ * Mapping table from "enum tomoyo_network_acl_index" to
+ * "enum tomoyo_mac_index" for unix domain socket.
+ */
+static const u8 tomoyo_unix2mac
+[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = {
+	[SOCK_STREAM] = {
+		[TOMOYO_NETWORK_BIND]    = TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
+		[TOMOYO_NETWORK_LISTEN]  =
+		TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
+		[TOMOYO_NETWORK_CONNECT] =
+		TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
+	},
+	[SOCK_DGRAM] = {
+		[TOMOYO_NETWORK_BIND]    = TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND,
+		[TOMOYO_NETWORK_SEND]    = TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND,
+	},
+	[SOCK_SEQPACKET] = {
+		[TOMOYO_NETWORK_BIND]    =
+		TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND,
+		[TOMOYO_NETWORK_LISTEN]  =
+		TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
+		[TOMOYO_NETWORK_CONNECT] =
+		TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
+	},
+};
+
+/**
+ * tomoyo_same_inet_acl - Check for duplicated "struct tomoyo_inet_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_inet_acl(const struct tomoyo_acl_info *a,
+				 const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_inet_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_inet_acl *p2 = container_of(b, typeof(*p2), head);
+
+	return p1->protocol == p2->protocol &&
+		tomoyo_same_ipaddr_union(&p1->address, &p2->address) &&
+		tomoyo_same_number_union(&p1->port, &p2->port);
+}
+
+/**
+ * tomoyo_same_unix_acl - Check for duplicated "struct tomoyo_unix_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
+static bool tomoyo_same_unix_acl(const struct tomoyo_acl_info *a,
+				 const struct tomoyo_acl_info *b)
+{
+	const struct tomoyo_unix_acl *p1 = container_of(a, typeof(*p1), head);
+	const struct tomoyo_unix_acl *p2 = container_of(b, typeof(*p2), head);
+
+	return p1->protocol == p2->protocol &&
+		tomoyo_same_name_union(&p1->name, &p2->name);
+}
+
+/**
+ * tomoyo_merge_inet_acl - Merge duplicated "struct tomoyo_inet_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a,
+				  struct tomoyo_acl_info *b,
+				  const bool is_delete)
+{
+	u8 * const a_perm =
+		&container_of(a, struct tomoyo_inet_acl, head)->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm;
+
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_merge_unix_acl - Merge duplicated "struct tomoyo_unix_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
+static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a,
+				  struct tomoyo_acl_info *b,
+				  const bool is_delete)
+{
+	u8 * const a_perm =
+		&container_of(a, struct tomoyo_unix_acl, head)->perm;
+	u8 perm = *a_perm;
+	const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm;
+
+	if (is_delete)
+		perm &= ~b_perm;
+	else
+		perm |= b_perm;
+	*a_perm = perm;
+	return !perm;
+}
+
+/**
+ * tomoyo_write_inet_network - Write "struct tomoyo_inet_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_inet_network(struct tomoyo_acl_param *param)
+{
+	struct tomoyo_inet_acl e = { .head.type = TOMOYO_TYPE_INET_ACL };
+	int error = -EINVAL;
+	u8 type;
+	const char *protocol = tomoyo_read_token(param);
+	const char *operation = tomoyo_read_token(param);
+
+	for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++)
+		if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol]))
+			break;
+	for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++)
+		if (tomoyo_permstr(operation, tomoyo_socket_keyword[type]))
+			e.perm |= 1 << type;
+	if (e.protocol == TOMOYO_SOCK_MAX || !e.perm)
+		return -EINVAL;
+	if (param->data[0] == '@') {
+		param->data++;
+		e.address.group =
+			tomoyo_get_group(param, TOMOYO_ADDRESS_GROUP);
+		if (!e.address.group)
+			return -ENOMEM;
+	} else {
+		if (!tomoyo_parse_ipaddr_union(param, &e.address))
+			goto out;
+	}
+	if (!tomoyo_parse_number_union(param, &e.port) ||
+	    e.port.values[1] > 65535)
+		goto out;
+	error = tomoyo_update_domain(&e.head, sizeof(e), param,
+				     tomoyo_same_inet_acl,
+				     tomoyo_merge_inet_acl);
+out:
+	tomoyo_put_group(e.address.group);
+	tomoyo_put_number_union(&e.port);
+	return error;
+}
+
+/**
+ * tomoyo_write_unix_network - Write "struct tomoyo_unix_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_unix_network(struct tomoyo_acl_param *param)
+{
+	struct tomoyo_unix_acl e = { .head.type = TOMOYO_TYPE_UNIX_ACL };
+	int error;
+	u8 type;
+	const char *protocol = tomoyo_read_token(param);
+	const char *operation = tomoyo_read_token(param);
+
+	for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++)
+		if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol]))
+			break;
+	for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++)
+		if (tomoyo_permstr(operation, tomoyo_socket_keyword[type]))
+			e.perm |= 1 << type;
+	if (e.protocol == TOMOYO_SOCK_MAX || !e.perm)
+		return -EINVAL;
+	if (!tomoyo_parse_name_union(param, &e.name))
+		return -EINVAL;
+	error = tomoyo_update_domain(&e.head, sizeof(e), param,
+				     tomoyo_same_unix_acl,
+				     tomoyo_merge_unix_acl);
+	tomoyo_put_name_union(&e.name);
+	return error;
+}
+
+/**
+ * tomoyo_audit_net_log - Audit network log.
+ *
+ * @r:         Pointer to "struct tomoyo_request_info".
+ * @family:    Name of socket family ("inet" or "unix").
+ * @protocol:  Name of protocol in @family.
+ * @operation: Name of socket operation.
+ * @address:   Name of address.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_net_log(struct tomoyo_request_info *r,
+				const char *family, const u8 protocol,
+				const u8 operation, const char *address)
+{
+	return tomoyo_supervisor(r, "network %s %s %s %s\n", family,
+				 tomoyo_proto_keyword[protocol],
+				 tomoyo_socket_keyword[operation], address);
+}
+
+/**
+ * tomoyo_audit_inet_log - Audit INET network log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_inet_log(struct tomoyo_request_info *r)
+{
+	char buf[128];
+	int len;
+	const __be32 *address = r->param.inet_network.address;
+
+	if (r->param.inet_network.is_ipv6)
+		tomoyo_print_ipv6(buf, sizeof(buf), (const struct in6_addr *)
+				  address, (const struct in6_addr *) address);
+	else
+		tomoyo_print_ipv4(buf, sizeof(buf), address, address);
+	len = strlen(buf);
+	snprintf(buf + len, sizeof(buf) - len, " %u",
+		 r->param.inet_network.port);
+	return tomoyo_audit_net_log(r, "inet", r->param.inet_network.protocol,
+				    r->param.inet_network.operation, buf);
+}
+
+/**
+ * tomoyo_audit_unix_log - Audit UNIX network log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_unix_log(struct tomoyo_request_info *r)
+{
+	return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol,
+				    r->param.unix_network.operation,
+				    r->param.unix_network.address->name);
+}
+
+/**
+ * tomoyo_check_inet_acl - Check permission for inet domain socket operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_inet_acl(struct tomoyo_request_info *r,
+				  const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_inet_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+	const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4;
+
+	if (!(acl->perm & (1 << r->param.inet_network.operation)) ||
+	    !tomoyo_compare_number_union(r->param.inet_network.port,
+					 &acl->port))
+		return false;
+	if (acl->address.group)
+		return tomoyo_address_matches_group
+			(r->param.inet_network.is_ipv6,
+			 r->param.inet_network.address, acl->address.group);
+	return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 &&
+		memcmp(&acl->address.ip[0],
+		       r->param.inet_network.address, size) <= 0 &&
+		memcmp(r->param.inet_network.address,
+		       &acl->address.ip[1], size) <= 0;
+}
+
+/**
+ * tomoyo_check_unix_acl - Check permission for unix domain socket operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_unix_acl(struct tomoyo_request_info *r,
+				  const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_unix_acl *acl =
+		container_of(ptr, typeof(*acl), head);
+
+	return (acl->perm & (1 << r->param.unix_network.operation)) &&
+		tomoyo_compare_name_union(r->param.unix_network.address,
+					  &acl->name);
+}
+
+/**
+ * tomoyo_inet_entry - Check permission for INET network operation.
+ *
+ * @address: Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_inet_entry(const struct tomoyo_addr_info *address)
+{
+	const int idx = tomoyo_read_lock();
+	struct tomoyo_request_info r;
+	int error = 0;
+	const u8 type = tomoyo_inet2mac[address->protocol][address->operation];
+
+	if (type && tomoyo_init_request_info(&r, NULL, type)
+	    != TOMOYO_CONFIG_DISABLED) {
+		r.param_type = TOMOYO_TYPE_INET_ACL;
+		r.param.inet_network.protocol = address->protocol;
+		r.param.inet_network.operation = address->operation;
+		r.param.inet_network.is_ipv6 = address->inet.is_ipv6;
+		r.param.inet_network.address = address->inet.address;
+		r.param.inet_network.port = ntohs(address->inet.port);
+		do {
+			tomoyo_check_acl(&r, tomoyo_check_inet_acl);
+			error = tomoyo_audit_inet_log(&r);
+		} while (error == TOMOYO_RETRY_REQUEST);
+	}
+	tomoyo_read_unlock(idx);
+	return error;
+}
+
+/**
+ * tomoyo_check_inet_address - Check permission for inet domain socket's operation.
+ *
+ * @addr:     Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ * @port:     Port number.
+ * @address:  Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_inet_address(const struct sockaddr *addr,
+				     const unsigned int addr_len,
+				     const u16 port,
+				     struct tomoyo_addr_info *address)
+{
+	struct tomoyo_inet_addr_info *i = &address->inet;
+
+	switch (addr->sa_family) {
+	case AF_INET6:
+		if (addr_len < SIN6_LEN_RFC2133)
+			goto skip;
+		i->is_ipv6 = true;
+		i->address = (__be32 *)
+			((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
+		i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
+		break;
+	case AF_INET:
+		if (addr_len < sizeof(struct sockaddr_in))
+			goto skip;
+		i->is_ipv6 = false;
+		i->address = (__be32 *)
+			&((struct sockaddr_in *) addr)->sin_addr;
+		i->port = ((struct sockaddr_in *) addr)->sin_port;
+		break;
+	default:
+		goto skip;
+	}
+	if (address->protocol == SOCK_RAW)
+		i->port = htons(port);
+	return tomoyo_inet_entry(address);
+skip:
+	return 0;
+}
+
+/**
+ * tomoyo_unix_entry - Check permission for UNIX network operation.
+ *
+ * @address: Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_unix_entry(const struct tomoyo_addr_info *address)
+{
+	const int idx = tomoyo_read_lock();
+	struct tomoyo_request_info r;
+	int error = 0;
+	const u8 type = tomoyo_unix2mac[address->protocol][address->operation];
+
+	if (type && tomoyo_init_request_info(&r, NULL, type)
+	    != TOMOYO_CONFIG_DISABLED) {
+		char *buf = address->unix0.addr;
+		int len = address->unix0.addr_len - sizeof(sa_family_t);
+
+		if (len <= 0) {
+			buf = "anonymous";
+			len = 9;
+		} else if (buf[0]) {
+			len = strnlen(buf, len);
+		}
+		buf = tomoyo_encode2(buf, len);
+		if (buf) {
+			struct tomoyo_path_info addr;
+
+			addr.name = buf;
+			tomoyo_fill_path_info(&addr);
+			r.param_type = TOMOYO_TYPE_UNIX_ACL;
+			r.param.unix_network.protocol = address->protocol;
+			r.param.unix_network.operation = address->operation;
+			r.param.unix_network.address = &addr;
+			do {
+				tomoyo_check_acl(&r, tomoyo_check_unix_acl);
+				error = tomoyo_audit_unix_log(&r);
+			} while (error == TOMOYO_RETRY_REQUEST);
+			kfree(buf);
+		} else
+			error = -ENOMEM;
+	}
+	tomoyo_read_unlock(idx);
+	return error;
+}
+
+/**
+ * tomoyo_check_unix_address - Check permission for unix domain socket's operation.
+ *
+ * @addr:     Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ * @address:  Pointer to "struct tomoyo_addr_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_check_unix_address(struct sockaddr *addr,
+				     const unsigned int addr_len,
+				     struct tomoyo_addr_info *address)
+{
+	struct tomoyo_unix_addr_info *u = &address->unix0;
+
+	if (addr->sa_family != AF_UNIX)
+		return 0;
+	u->addr = ((struct sockaddr_un *) addr)->sun_path;
+	u->addr_len = addr_len;
+	return tomoyo_unix_entry(address);
+}
+
+/**
+ * tomoyo_kernel_service - Check whether I'm kernel service or not.
+ *
+ * Returns true if I'm kernel service, false otherwise.
+ */
+static bool tomoyo_kernel_service(void)
+{
+	/* Nothing to do if I am a kernel service. */
+	return segment_eq(get_fs(), KERNEL_DS);
+}
+
+/**
+ * tomoyo_sock_family - Get socket's family.
+ *
+ * @sk: Pointer to "struct sock".
+ *
+ * Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
+ */
+static u8 tomoyo_sock_family(struct sock *sk)
+{
+	u8 family;
+
+	if (tomoyo_kernel_service())
+		return 0;
+	family = sk->sk_family;
+	switch (family) {
+	case PF_INET:
+	case PF_INET6:
+	case PF_UNIX:
+		return family;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * tomoyo_socket_listen_permission - Check permission for listening a socket.
+ *
+ * @sock: Pointer to "struct socket".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_listen_permission(struct socket *sock)
+{
+	struct tomoyo_addr_info address;
+	const u8 family = tomoyo_sock_family(sock->sk);
+	const unsigned int type = sock->type;
+	struct sockaddr_storage addr;
+	int addr_len;
+
+	if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
+		return 0;
+	{
+		const int error = sock->ops->getname(sock, (struct sockaddr *)
+						     &addr, &addr_len, 0);
+
+		if (error)
+			return error;
+	}
+	address.protocol = type;
+	address.operation = TOMOYO_NETWORK_LISTEN;
+	if (family == PF_UNIX)
+		return tomoyo_check_unix_address((struct sockaddr *) &addr,
+						 addr_len, &address);
+	return tomoyo_check_inet_address((struct sockaddr *) &addr, addr_len,
+					 0, &address);
+}
+
+/**
+ * tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket.
+ *
+ * @sock:     Pointer to "struct socket".
+ * @addr:     Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_connect_permission(struct socket *sock,
+				     struct sockaddr *addr, int addr_len)
+{
+	struct tomoyo_addr_info address;
+	const u8 family = tomoyo_sock_family(sock->sk);
+	const unsigned int type = sock->type;
+
+	if (!family)
+		return 0;
+	address.protocol = type;
+	switch (type) {
+	case SOCK_DGRAM:
+	case SOCK_RAW:
+		address.operation = TOMOYO_NETWORK_SEND;
+		break;
+	case SOCK_STREAM:
+	case SOCK_SEQPACKET:
+		address.operation = TOMOYO_NETWORK_CONNECT;
+		break;
+	default:
+		return 0;
+	}
+	if (family == PF_UNIX)
+		return tomoyo_check_unix_address(addr, addr_len, &address);
+	return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
+					 &address);
+}
+
+/**
+ * tomoyo_socket_bind_permission - Check permission for setting the local address of a socket.
+ *
+ * @sock:     Pointer to "struct socket".
+ * @addr:     Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
+				  int addr_len)
+{
+	struct tomoyo_addr_info address;
+	const u8 family = tomoyo_sock_family(sock->sk);
+	const unsigned int type = sock->type;
+
+	if (!family)
+		return 0;
+	switch (type) {
+	case SOCK_STREAM:
+	case SOCK_DGRAM:
+	case SOCK_RAW:
+	case SOCK_SEQPACKET:
+		address.protocol = type;
+		address.operation = TOMOYO_NETWORK_BIND;
+		break;
+	default:
+		return 0;
+	}
+	if (family == PF_UNIX)
+		return tomoyo_check_unix_address(addr, addr_len, &address);
+	return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
+					 &address);
+}
+
+/**
+ * tomoyo_socket_sendmsg_permission - Check permission for sending a datagram.
+ *
+ * @sock: Pointer to "struct socket".
+ * @msg:  Pointer to "struct msghdr".
+ * @size: Unused.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
+				     int size)
+{
+	struct tomoyo_addr_info address;
+	const u8 family = tomoyo_sock_family(sock->sk);
+	const unsigned int type = sock->type;
+
+	if (!msg->msg_name || !family ||
+	    (type != SOCK_DGRAM && type != SOCK_RAW))
+		return 0;
+	address.protocol = type;
+	address.operation = TOMOYO_NETWORK_SEND;
+	if (family == PF_UNIX)
+		return tomoyo_check_unix_address((struct sockaddr *)
+						 msg->msg_name,
+						 msg->msg_namelen, &address);
+	return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name,
+					 msg->msg_namelen,
+					 sock->sk->sk_protocol, &address);
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/realpath.c b/ap/os/linux/linux-3.4.x/security/tomoyo/realpath.c
new file mode 100644
index 0000000..80a09c3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/realpath.c
@@ -0,0 +1,328 @@
+/*
+ * security/tomoyo/realpath.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/magic.h>
+
+/**
+ * tomoyo_encode2 - Encode binary string to ascii string.
+ *
+ * @str:     String in binary format.
+ * @str_len: Size of @str in byte.
+ *
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_encode2(const char *str, int str_len)
+{
+	int i;
+	int len = 0;
+	const char *p = str;
+	char *cp;
+	char *cp0;
+
+	if (!p)
+		return NULL;
+	for (i = 0; i < str_len; i++) {
+		const unsigned char c = p[i];
+
+		if (c == '\\')
+			len += 2;
+		else if (c > ' ' && c < 127)
+			len++;
+		else
+			len += 4;
+	}
+	len++;
+	/* Reserve space for appending "/". */
+	cp = kzalloc(len + 10, GFP_NOFS);
+	if (!cp)
+		return NULL;
+	cp0 = cp;
+	p = str;
+	for (i = 0; i < str_len; i++) {
+		const unsigned char c = p[i];
+
+		if (c == '\\') {
+			*cp++ = '\\';
+			*cp++ = '\\';
+		} else if (c > ' ' && c < 127) {
+			*cp++ = c;
+		} else {
+			*cp++ = '\\';
+			*cp++ = (c >> 6) + '0';
+			*cp++ = ((c >> 3) & 7) + '0';
+			*cp++ = (c & 7) + '0';
+		}
+	}
+	return cp0;
+}
+
+/**
+ * tomoyo_encode - Encode binary string to ascii string.
+ *
+ * @str: String in binary format.
+ *
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_encode(const char *str)
+{
+	return str ? tomoyo_encode2(str, strlen(str)) : NULL;
+}
+
+/**
+ * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
+ *
+ * @path:   Pointer to "struct path".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ */
+static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
+				      const int buflen)
+{
+	char *pos = ERR_PTR(-ENOMEM);
+	if (buflen >= 256) {
+		/* go to whatever namespace root we are under */
+		pos = d_absolute_path(path, buffer, buflen - 1);
+		if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
+			struct inode *inode = path->dentry->d_inode;
+			if (inode && S_ISDIR(inode->i_mode)) {
+				buffer[buflen - 2] = '/';
+				buffer[buflen - 1] = '\0';
+			}
+		}
+	}
+	return pos;
+}
+
+/**
+ * tomoyo_get_dentry_path - Get the path of a dentry.
+ *
+ * @dentry: Pointer to "struct dentry".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ */
+static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
+				    const int buflen)
+{
+	char *pos = ERR_PTR(-ENOMEM);
+	if (buflen >= 256) {
+		pos = dentry_path_raw(dentry, buffer, buflen - 1);
+		if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
+			struct inode *inode = dentry->d_inode;
+			if (inode && S_ISDIR(inode->i_mode)) {
+				buffer[buflen - 2] = '/';
+				buffer[buflen - 1] = '\0';
+			}
+		}
+	}
+	return pos;
+}
+
+/**
+ * tomoyo_get_local_path - Get the path of a dentry.
+ *
+ * @dentry: Pointer to "struct dentry".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ */
+static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
+				   const int buflen)
+{
+	struct super_block *sb = dentry->d_sb;
+	char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
+	if (IS_ERR(pos))
+		return pos;
+	/* Convert from $PID to self if $PID is current thread. */
+	if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
+		char *ep;
+		const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
+		if (*ep == '/' && pid && pid ==
+		    task_tgid_nr_ns(current, sb->s_fs_info)) {
+			pos = ep - 5;
+			if (pos < buffer)
+				goto out;
+			memmove(pos, "/self", 5);
+		}
+		goto prepend_filesystem_name;
+	}
+	/* Use filesystem name for unnamed devices. */
+	if (!MAJOR(sb->s_dev))
+		goto prepend_filesystem_name;
+	{
+		struct inode *inode = sb->s_root->d_inode;
+		/*
+		 * Use filesystem name if filesystem does not support rename()
+		 * operation.
+		 */
+		if (inode->i_op && !inode->i_op->rename)
+			goto prepend_filesystem_name;
+	}
+	/* Prepend device name. */
+	{
+		char name[64];
+		int name_len;
+		const dev_t dev = sb->s_dev;
+		name[sizeof(name) - 1] = '\0';
+		snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
+			 MINOR(dev));
+		name_len = strlen(name);
+		pos -= name_len;
+		if (pos < buffer)
+			goto out;
+		memmove(pos, name, name_len);
+		return pos;
+	}
+	/* Prepend filesystem name. */
+prepend_filesystem_name:
+	{
+		const char *name = sb->s_type->name;
+		const int name_len = strlen(name);
+		pos -= name_len + 1;
+		if (pos < buffer)
+			goto out;
+		memmove(pos, name, name_len);
+		pos[name_len] = ':';
+	}
+	return pos;
+out:
+	return ERR_PTR(-ENOMEM);
+}
+
+/**
+ * tomoyo_get_socket_name - Get the name of a socket.
+ *
+ * @path:   Pointer to "struct path".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer.
+ */
+static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
+				    const int buflen)
+{
+	struct inode *inode = path->dentry->d_inode;
+	struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+	struct sock *sk = sock ? sock->sk : NULL;
+	if (sk) {
+		snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
+			 "protocol=%u]", sk->sk_family, sk->sk_type,
+			 sk->sk_protocol);
+	} else {
+		snprintf(buffer, buflen, "socket:[unknown]");
+	}
+	return buffer;
+}
+
+/**
+ * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns the realpath of the given @path on success, NULL otherwise.
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ * Characters out of 0x20 < c < 0x7F range are converted to
+ * \ooo style octal string.
+ * Character \ is converted to \\ string.
+ *
+ * These functions use kzalloc(), so the caller must call kfree()
+ * if these functions didn't return NULL.
+ */
+char *tomoyo_realpath_from_path(struct path *path)
+{
+	char *buf = NULL;
+	char *name = NULL;
+	unsigned int buf_len = PAGE_SIZE / 2;
+	struct dentry *dentry = path->dentry;
+	struct super_block *sb;
+	if (!dentry)
+		return NULL;
+	sb = dentry->d_sb;
+	while (1) {
+		char *pos;
+		struct inode *inode;
+		buf_len <<= 1;
+		kfree(buf);
+		buf = kmalloc(buf_len, GFP_NOFS);
+		if (!buf)
+			break;
+		/* To make sure that pos is '\0' terminated. */
+		buf[buf_len - 1] = '\0';
+		/* Get better name for socket. */
+		if (sb->s_magic == SOCKFS_MAGIC) {
+			pos = tomoyo_get_socket_name(path, buf, buf_len - 1);
+			goto encode;
+		}
+		/* For "pipe:[\$]". */
+		if (dentry->d_op && dentry->d_op->d_dname) {
+			pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
+			goto encode;
+		}
+		inode = sb->s_root->d_inode;
+		/*
+		 * Get local name for filesystems without rename() operation
+		 * or dentry without vfsmount.
+		 */
+		if (!path->mnt || (inode->i_op && !inode->i_op->rename))
+			pos = tomoyo_get_local_path(path->dentry, buf,
+						    buf_len - 1);
+		/* Get absolute name for the rest. */
+		else {
+			pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
+			/*
+			 * Fall back to local name if absolute name is not
+			 * available.
+			 */
+			if (pos == ERR_PTR(-EINVAL))
+				pos = tomoyo_get_local_path(path->dentry, buf,
+							    buf_len - 1);
+		}
+encode:
+		if (IS_ERR(pos))
+			continue;
+		name = tomoyo_encode(pos);
+		break;
+	}
+	kfree(buf);
+	if (!name)
+		tomoyo_warn_oom(__func__);
+	return name;
+}
+
+/**
+ * tomoyo_realpath_nofollow - Get realpath of a pathname.
+ *
+ * @pathname: The pathname to solve.
+ *
+ * Returns the realpath of @pathname on success, NULL otherwise.
+ */
+char *tomoyo_realpath_nofollow(const char *pathname)
+{
+	struct path path;
+
+	if (pathname && kern_path(pathname, 0, &path) == 0) {
+		char *buf = tomoyo_realpath_from_path(&path);
+		path_put(&path);
+		return buf;
+	}
+	return NULL;
+}
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/securityfs_if.c b/ap/os/linux/linux-3.4.x/security/tomoyo/securityfs_if.c
new file mode 100644
index 0000000..8592f2f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/securityfs_if.c
@@ -0,0 +1,273 @@
+/*
+ * security/tomoyo/securityfs_if.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/security.h>
+#include "common.h"
+
+/**
+ * tomoyo_check_task_acl - Check permission for task operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
+static bool tomoyo_check_task_acl(struct tomoyo_request_info *r,
+				  const struct tomoyo_acl_info *ptr)
+{
+	const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl),
+							 head);
+	return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname);
+}
+
+/**
+ * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Domainname to transit to.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ *
+ * If domain transition was permitted but the domain transition failed, this
+ * function returns error rather than terminating current thread with SIGKILL.
+ */
+static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	char *data;
+	int error;
+	if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
+		return -ENOMEM;
+	data = kzalloc(count + 1, GFP_NOFS);
+	if (!data)
+		return -ENOMEM;
+	if (copy_from_user(data, buf, count)) {
+		error = -EFAULT;
+		goto out;
+	}
+	tomoyo_normalize_line(data);
+	if (tomoyo_correct_domain(data)) {
+		const int idx = tomoyo_read_lock();
+		struct tomoyo_path_info name;
+		struct tomoyo_request_info r;
+		name.name = data;
+		tomoyo_fill_path_info(&name);
+		/* Check "task manual_domain_transition" permission. */
+		tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+		r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL;
+		r.param.task.domainname = &name;
+		tomoyo_check_acl(&r, tomoyo_check_task_acl);
+		if (!r.granted)
+			error = -EPERM;
+		else {
+			struct tomoyo_domain_info *new_domain =
+				tomoyo_assign_domain(data, true);
+			if (!new_domain) {
+				error = -ENOENT;
+			} else {
+				struct cred *cred = prepare_creds();
+				if (!cred) {
+					error = -ENOMEM;
+				} else {
+					struct tomoyo_domain_info *old_domain =
+						cred->security;
+					cred->security = new_domain;
+					atomic_inc(&new_domain->users);
+					atomic_dec(&old_domain->users);
+					commit_creds(cred);
+					error = 0;
+				}
+			}
+		}
+		tomoyo_read_unlock(idx);
+	} else
+		error = -EINVAL;
+out:
+	kfree(data);
+	return error ? error : count;
+}
+
+/**
+ * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Domainname which current thread belongs to.
+ * @count: Size of @buf.
+ * @ppos:  Bytes read by now.
+ *
+ * Returns read size on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read_self(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	const char *domain = tomoyo_domain()->domainname->name;
+	loff_t len = strlen(domain);
+	loff_t pos = *ppos;
+	if (pos >= len || !count)
+		return 0;
+	len -= pos;
+	if (count < len)
+		len = count;
+	if (copy_to_user(buf, domain + pos, len))
+		return -EFAULT;
+	*ppos += len;
+	return len;
+}
+
+/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */
+static const struct file_operations tomoyo_self_operations = {
+	.write = tomoyo_write_self,
+	.read  = tomoyo_read_self,
+};
+
+/**
+ * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_open(struct inode *inode, struct file *file)
+{
+	const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
+		- ((u8 *) NULL);
+	return tomoyo_open_control(key, file);
+}
+
+/**
+ * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file:  Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_release(struct inode *inode, struct file *file)
+{
+	return tomoyo_close_control(file->private_data);
+}
+
+/**
+ * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table". Maybe NULL.
+ *
+ * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
+ * POLLOUT | POLLWRNORM otherwise.
+ */
+static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
+{
+	return tomoyo_poll_control(file, wait);
+}
+
+/**
+ * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
+			   loff_t *ppos)
+{
+	return tomoyo_read_control(file->private_data, buf, count);
+}
+
+/**
+ * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file:  Pointer to "struct file".
+ * @buf:   Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos:  Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ */
+static ssize_t tomoyo_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	return tomoyo_write_control(file->private_data, buf, count);
+}
+
+/*
+ * tomoyo_operations is a "struct file_operations" which is used for handling
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
+ * See tomoyo_io_buffer for internals.
+ */
+static const struct file_operations tomoyo_operations = {
+	.open    = tomoyo_open,
+	.release = tomoyo_release,
+	.poll    = tomoyo_poll,
+	.read    = tomoyo_read,
+	.write   = tomoyo_write,
+	.llseek  = noop_llseek,
+};
+
+/**
+ * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
+ *
+ * @name:   The name of the interface file.
+ * @mode:   The permission of the interface file.
+ * @parent: The parent directory.
+ * @key:    Type of interface.
+ *
+ * Returns nothing.
+ */
+static void __init tomoyo_create_entry(const char *name, const umode_t mode,
+				       struct dentry *parent, const u8 key)
+{
+	securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
+			       &tomoyo_operations);
+}
+
+/**
+ * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_initerface_init(void)
+{
+	struct dentry *tomoyo_dir;
+
+	/* Don't create securityfs entries unless registered. */
+	if (current_cred()->security != &tomoyo_kernel_domain)
+		return 0;
+
+	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
+	tomoyo_create_entry("query",            0600, tomoyo_dir,
+			    TOMOYO_QUERY);
+	tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
+			    TOMOYO_DOMAINPOLICY);
+	tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
+			    TOMOYO_EXCEPTIONPOLICY);
+	tomoyo_create_entry("audit",            0400, tomoyo_dir,
+			    TOMOYO_AUDIT);
+	tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
+			    TOMOYO_PROCESS_STATUS);
+	tomoyo_create_entry("stat",             0644, tomoyo_dir,
+			    TOMOYO_STAT);
+	tomoyo_create_entry("profile",          0600, tomoyo_dir,
+			    TOMOYO_PROFILE);
+	tomoyo_create_entry("manager",          0600, tomoyo_dir,
+			    TOMOYO_MANAGER);
+	tomoyo_create_entry("version",          0400, tomoyo_dir,
+			    TOMOYO_VERSION);
+	securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL,
+			       &tomoyo_self_operations);
+	tomoyo_load_builtin_policy();
+	return 0;
+}
+
+fs_initcall(tomoyo_initerface_init);
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/tomoyo.c b/ap/os/linux/linux-3.4.x/security/tomoyo/tomoyo.c
new file mode 100644
index 0000000..620d37c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/tomoyo.c
@@ -0,0 +1,560 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/security.h>
+#include "common.h"
+
+/**
+ * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank().
+ *
+ * @new: Pointer to "struct cred".
+ * @gfp: Memory allocation flags.
+ *
+ * Returns 0.
+ */
+static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
+{
+	new->security = NULL;
+	return 0;
+}
+
+/**
+ * tomoyo_cred_prepare - Target for security_prepare_creds().
+ *
+ * @new: Pointer to "struct cred".
+ * @old: Pointer to "struct cred".
+ * @gfp: Memory allocation flags.
+ *
+ * Returns 0.
+ */
+static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
+			       gfp_t gfp)
+{
+	struct tomoyo_domain_info *domain = old->security;
+	new->security = domain;
+	if (domain)
+		atomic_inc(&domain->users);
+	return 0;
+}
+
+/**
+ * tomoyo_cred_transfer - Target for security_transfer_creds().
+ *
+ * @new: Pointer to "struct cred".
+ * @old: Pointer to "struct cred".
+ */
+static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
+{
+	tomoyo_cred_prepare(new, old, 0);
+}
+
+/**
+ * tomoyo_cred_free - Target for security_cred_free().
+ *
+ * @cred: Pointer to "struct cred".
+ */
+static void tomoyo_cred_free(struct cred *cred)
+{
+	struct tomoyo_domain_info *domain = cred->security;
+	if (domain)
+		atomic_dec(&domain->users);
+}
+
+/**
+ * tomoyo_bprm_set_creds - Target for security_bprm_set_creds().
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
+{
+	int rc;
+
+	rc = cap_bprm_set_creds(bprm);
+	if (rc)
+		return rc;
+
+	/*
+	 * Do only if this function is called for the first time of an execve
+	 * operation.
+	 */
+	if (bprm->cred_prepared)
+		return 0;
+#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+	/*
+	 * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested
+	 * for the first time.
+	 */
+	if (!tomoyo_policy_loaded)
+		tomoyo_load_policy(bprm->filename);
+#endif
+	/*
+	 * Release reference to "struct tomoyo_domain_info" stored inside
+	 * "bprm->cred->security". New reference to "struct tomoyo_domain_info"
+	 * stored inside "bprm->cred->security" will be acquired later inside
+	 * tomoyo_find_next_domain().
+	 */
+	atomic_dec(&((struct tomoyo_domain_info *)
+		     bprm->cred->security)->users);
+	/*
+	 * Tell tomoyo_bprm_check_security() is called for the first time of an
+	 * execve operation.
+	 */
+	bprm->cred->security = NULL;
+	return 0;
+}
+
+/**
+ * tomoyo_bprm_check_security - Target for security_bprm_check().
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
+{
+	struct tomoyo_domain_info *domain = bprm->cred->security;
+
+	/*
+	 * Execute permission is checked against pathname passed to do_execve()
+	 * using current domain.
+	 */
+	if (!domain) {
+		const int idx = tomoyo_read_lock();
+		const int err = tomoyo_find_next_domain(bprm);
+		tomoyo_read_unlock(idx);
+		return err;
+	}
+	/*
+	 * Read permission is checked against interpreters using next domain.
+	 */
+	return tomoyo_check_open_permission(domain, &bprm->file->f_path,
+					    O_RDONLY);
+}
+
+/**
+ * tomoyo_inode_getattr - Target for security_inode_getattr().
+ *
+ * @mnt:    Pointer to "struct vfsmount".
+ * @dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+	struct path path = { mnt, dentry };
+	return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL);
+}
+
+/**
+ * tomoyo_path_truncate - Target for security_path_truncate().
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_truncate(struct path *path)
+{
+	return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL);
+}
+
+/**
+ * tomoyo_path_unlink - Target for security_path_unlink().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
+{
+	struct path path = { parent->mnt, dentry };
+	return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL);
+}
+
+/**
+ * tomoyo_path_mkdir - Target for security_path_mkdir().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ * @mode:   DAC permission mode.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
+			     umode_t mode)
+{
+	struct path path = { parent->mnt, dentry };
+	return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
+				       mode & S_IALLUGO);
+}
+
+/**
+ * tomoyo_path_rmdir - Target for security_path_rmdir().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
+{
+	struct path path = { parent->mnt, dentry };
+	return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL);
+}
+
+/**
+ * tomoyo_path_symlink - Target for security_path_symlink().
+ *
+ * @parent:   Pointer to "struct path".
+ * @dentry:   Pointer to "struct dentry".
+ * @old_name: Symlink's content.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
+			       const char *old_name)
+{
+	struct path path = { parent->mnt, dentry };
+	return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name);
+}
+
+/**
+ * tomoyo_path_mknod - Target for security_path_mknod().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ * @mode:   DAC permission mode.
+ * @dev:    Device attributes.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
+			     umode_t mode, unsigned int dev)
+{
+	struct path path = { parent->mnt, dentry };
+	int type = TOMOYO_TYPE_CREATE;
+	const unsigned int perm = mode & S_IALLUGO;
+
+	switch (mode & S_IFMT) {
+	case S_IFCHR:
+		type = TOMOYO_TYPE_MKCHAR;
+		break;
+	case S_IFBLK:
+		type = TOMOYO_TYPE_MKBLOCK;
+		break;
+	default:
+		goto no_dev;
+	}
+	return tomoyo_mkdev_perm(type, &path, perm, dev);
+ no_dev:
+	switch (mode & S_IFMT) {
+	case S_IFIFO:
+		type = TOMOYO_TYPE_MKFIFO;
+		break;
+	case S_IFSOCK:
+		type = TOMOYO_TYPE_MKSOCK;
+		break;
+	}
+	return tomoyo_path_number_perm(type, &path, perm);
+}
+
+/**
+ * tomoyo_path_link - Target for security_path_link().
+ *
+ * @old_dentry: Pointer to "struct dentry".
+ * @new_dir:    Pointer to "struct path".
+ * @new_dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
+			    struct dentry *new_dentry)
+{
+	struct path path1 = { new_dir->mnt, old_dentry };
+	struct path path2 = { new_dir->mnt, new_dentry };
+	return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
+}
+
+/**
+ * tomoyo_path_rename - Target for security_path_rename().
+ *
+ * @old_parent: Pointer to "struct path".
+ * @old_dentry: Pointer to "struct dentry".
+ * @new_parent: Pointer to "struct path".
+ * @new_dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_rename(struct path *old_parent,
+			      struct dentry *old_dentry,
+			      struct path *new_parent,
+			      struct dentry *new_dentry)
+{
+	struct path path1 = { old_parent->mnt, old_dentry };
+	struct path path2 = { new_parent->mnt, new_dentry };
+	return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2);
+}
+
+/**
+ * tomoyo_file_fcntl - Target for security_file_fcntl().
+ *
+ * @file: Pointer to "struct file".
+ * @cmd:  Command for fcntl().
+ * @arg:  Argument for @cmd.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
+			     unsigned long arg)
+{
+	if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
+		return 0;
+	return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path,
+					    O_WRONLY | (arg & O_APPEND));
+}
+
+/**
+ * tomoyo_dentry_open - Target for security_dentry_open().
+ *
+ * @f:    Pointer to "struct file".
+ * @cred: Pointer to "struct cred".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
+{
+	int flags = f->f_flags;
+	/* Don't check read permission here if called from do_execve(). */
+	if (current->in_execve)
+		return 0;
+	return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
+}
+
+/**
+ * tomoyo_file_ioctl - Target for security_file_ioctl().
+ *
+ * @file: Pointer to "struct file".
+ * @cmd:  Command for ioctl().
+ * @arg:  Argument for @cmd.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
+			     unsigned long arg)
+{
+	return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd);
+}
+
+/**
+ * tomoyo_path_chmod - Target for security_path_chmod().
+ *
+ * @path: Pointer to "struct path".
+ * @mode: DAC permission mode.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_chmod(struct path *path, umode_t mode)
+{
+	return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path,
+				       mode & S_IALLUGO);
+}
+
+/**
+ * tomoyo_path_chown - Target for security_path_chown().
+ *
+ * @path: Pointer to "struct path".
+ * @uid:  Owner ID.
+ * @gid:  Group ID.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+	int error = 0;
+	if (uid != (uid_t) -1)
+		error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid);
+	if (!error && gid != (gid_t) -1)
+		error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid);
+	return error;
+}
+
+/**
+ * tomoyo_path_chroot - Target for security_path_chroot().
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_path_chroot(struct path *path)
+{
+	return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL);
+}
+
+/**
+ * tomoyo_sb_mount - Target for security_sb_mount().
+ *
+ * @dev_name: Name of device file. Maybe NULL.
+ * @path:     Pointer to "struct path".
+ * @type:     Name of filesystem type. Maybe NULL.
+ * @flags:    Mount options.
+ * @data:     Optional data. Maybe NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_sb_mount(char *dev_name, struct path *path,
+			   char *type, unsigned long flags, void *data)
+{
+	return tomoyo_mount_permission(dev_name, path, type, flags, data);
+}
+
+/**
+ * tomoyo_sb_umount - Target for security_sb_umount().
+ *
+ * @mnt:   Pointer to "struct vfsmount".
+ * @flags: Unmount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
+{
+	struct path path = { mnt, mnt->mnt_root };
+	return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL);
+}
+
+/**
+ * tomoyo_sb_pivotroot - Target for security_sb_pivotroot().
+ *
+ * @old_path: Pointer to "struct path".
+ * @new_path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)
+{
+	return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path);
+}
+
+/**
+ * tomoyo_socket_listen - Check permission for listen().
+ *
+ * @sock:    Pointer to "struct socket".
+ * @backlog: Backlog parameter.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_listen(struct socket *sock, int backlog)
+{
+	return tomoyo_socket_listen_permission(sock);
+}
+
+/**
+ * tomoyo_socket_connect - Check permission for connect().
+ *
+ * @sock:     Pointer to "struct socket".
+ * @addr:     Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr,
+				 int addr_len)
+{
+	return tomoyo_socket_connect_permission(sock, addr, addr_len);
+}
+
+/**
+ * tomoyo_socket_bind - Check permission for bind().
+ *
+ * @sock:     Pointer to "struct socket".
+ * @addr:     Pointer to "struct sockaddr".
+ * @addr_len: Size of @addr.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr,
+			      int addr_len)
+{
+	return tomoyo_socket_bind_permission(sock, addr, addr_len);
+}
+
+/**
+ * tomoyo_socket_sendmsg - Check permission for sendmsg().
+ *
+ * @sock: Pointer to "struct socket".
+ * @msg:  Pointer to "struct msghdr".
+ * @size: Size of message.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+				 int size)
+{
+	return tomoyo_socket_sendmsg_permission(sock, msg, size);
+}
+
+/*
+ * tomoyo_security_ops is a "struct security_operations" which is used for
+ * registering TOMOYO.
+ */
+static struct security_operations tomoyo_security_ops = {
+	.name                = "tomoyo",
+	.cred_alloc_blank    = tomoyo_cred_alloc_blank,
+	.cred_prepare        = tomoyo_cred_prepare,
+	.cred_transfer	     = tomoyo_cred_transfer,
+	.cred_free           = tomoyo_cred_free,
+	.bprm_set_creds      = tomoyo_bprm_set_creds,
+	.bprm_check_security = tomoyo_bprm_check_security,
+	.file_fcntl          = tomoyo_file_fcntl,
+	.dentry_open         = tomoyo_dentry_open,
+	.path_truncate       = tomoyo_path_truncate,
+	.path_unlink         = tomoyo_path_unlink,
+	.path_mkdir          = tomoyo_path_mkdir,
+	.path_rmdir          = tomoyo_path_rmdir,
+	.path_symlink        = tomoyo_path_symlink,
+	.path_mknod          = tomoyo_path_mknod,
+	.path_link           = tomoyo_path_link,
+	.path_rename         = tomoyo_path_rename,
+	.inode_getattr       = tomoyo_inode_getattr,
+	.file_ioctl          = tomoyo_file_ioctl,
+	.path_chmod          = tomoyo_path_chmod,
+	.path_chown          = tomoyo_path_chown,
+	.path_chroot         = tomoyo_path_chroot,
+	.sb_mount            = tomoyo_sb_mount,
+	.sb_umount           = tomoyo_sb_umount,
+	.sb_pivotroot        = tomoyo_sb_pivotroot,
+	.socket_bind         = tomoyo_socket_bind,
+	.socket_connect      = tomoyo_socket_connect,
+	.socket_listen       = tomoyo_socket_listen,
+	.socket_sendmsg      = tomoyo_socket_sendmsg,
+};
+
+/* Lock for GC. */
+struct srcu_struct tomoyo_ss;
+
+/**
+ * tomoyo_init - Register TOMOYO Linux as a LSM module.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_init(void)
+{
+	struct cred *cred = (struct cred *) current_cred();
+
+	if (!security_module_enable(&tomoyo_security_ops))
+		return 0;
+	/* register ourselves with the security framework */
+	if (register_security(&tomoyo_security_ops) ||
+	    init_srcu_struct(&tomoyo_ss))
+		panic("Failure registering TOMOYO Linux");
+	printk(KERN_INFO "TOMOYO Linux initialized\n");
+	cred->security = &tomoyo_kernel_domain;
+	tomoyo_mm_init();
+	return 0;
+}
+
+security_initcall(tomoyo_init);
diff --git a/ap/os/linux/linux-3.4.x/security/tomoyo/util.c b/ap/os/linux/linux-3.4.x/security/tomoyo/util.c
new file mode 100644
index 0000000..867558c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/security/tomoyo/util.c
@@ -0,0 +1,1090 @@
+/*
+ * security/tomoyo/util.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Lock for protecting policy. */
+DEFINE_MUTEX(tomoyo_policy_lock);
+
+/* Has /sbin/init started? */
+bool tomoyo_policy_loaded;
+
+/*
+ * Mapping table from "enum tomoyo_mac_index" to
+ * "enum tomoyo_mac_category_index".
+ */
+const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
+	/* CONFIG::file group */
+	[TOMOYO_MAC_FILE_EXECUTE]    = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_OPEN]       = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_CREATE]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_UNLINK]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_GETATTR]    = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_MKDIR]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_RMDIR]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_MKFIFO]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_MKSOCK]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_TRUNCATE]   = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_SYMLINK]    = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_MKBLOCK]    = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_MKCHAR]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_LINK]       = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_RENAME]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_CHMOD]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_CHOWN]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_CHGRP]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_IOCTL]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_CHROOT]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_MOUNT]      = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_UMOUNT]     = TOMOYO_MAC_CATEGORY_FILE,
+	[TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
+	/* CONFIG::network group */
+	[TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_INET_RAW_BIND]          =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_INET_RAW_SEND]          =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] =
+	TOMOYO_MAC_CATEGORY_NETWORK,
+	/* CONFIG::misc group */
+	[TOMOYO_MAC_ENVIRON]         = TOMOYO_MAC_CATEGORY_MISC,
+};
+
+/**
+ * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
+ *
+ * @time:  Seconds since 1970/01/01 00:00:00.
+ * @stamp: Pointer to "struct tomoyo_time".
+ *
+ * Returns nothing.
+ *
+ * This function does not handle Y2038 problem.
+ */
+void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp)
+{
+	static const u16 tomoyo_eom[2][12] = {
+		{ 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+		{ 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+	};
+	u16 y;
+	u8 m;
+	bool r;
+	stamp->sec = time % 60;
+	time /= 60;
+	stamp->min = time % 60;
+	time /= 60;
+	stamp->hour = time % 24;
+	time /= 24;
+	for (y = 1970; ; y++) {
+		const unsigned short days = (y & 3) ? 365 : 366;
+		if (time < days)
+			break;
+		time -= days;
+	}
+	r = (y & 3) == 0;
+	for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++)
+		;
+	if (m)
+		time -= tomoyo_eom[r][m - 1];
+	stamp->year = y;
+	stamp->month = ++m;
+	stamp->day = ++time;
+}
+
+/**
+ * tomoyo_permstr - Find permission keywords.
+ *
+ * @string: String representation for permissions in foo/bar/buz format.
+ * @keyword: Keyword to find from @string/
+ *
+ * Returns ture if @keyword was found in @string, false otherwise.
+ *
+ * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
+ */
+bool tomoyo_permstr(const char *string, const char *keyword)
+{
+	const char *cp = strstr(string, keyword);
+	if (cp)
+		return cp == string || *(cp - 1) == '/';
+	return false;
+}
+
+/**
+ * tomoyo_read_token - Read a word from a line.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns a word on success, "" otherwise.
+ *
+ * To allow the caller to skip NULL check, this function returns "" rather than
+ * NULL if there is no more words to read.
+ */
+char *tomoyo_read_token(struct tomoyo_acl_param *param)
+{
+	char *pos = param->data;
+	char *del = strchr(pos, ' ');
+	if (del)
+		*del++ = '\0';
+	else
+		del = pos + strlen(pos);
+	param->data = del;
+	return pos;
+}
+
+/**
+ * tomoyo_get_domainname - Read a domainname from a line.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns a domainname on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_domainname
+(struct tomoyo_acl_param *param)
+{
+	char *start = param->data;
+	char *pos = start;
+	while (*pos) {
+		if (*pos++ != ' ' || *pos++ == '/')
+			continue;
+		pos -= 2;
+		*pos++ = '\0';
+		break;
+	}
+	param->data = pos;
+	if (tomoyo_correct_domain(start))
+		return tomoyo_get_name(start);
+	return NULL;
+}
+
+/**
+ * tomoyo_parse_ulong - Parse an "unsigned long" value.
+ *
+ * @result: Pointer to "unsigned long".
+ * @str:    Pointer to string to parse.
+ *
+ * Returns one of values in "enum tomoyo_value_type".
+ *
+ * The @src is updated to point the first character after the value
+ * on success.
+ */
+u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+{
+	const char *cp = *str;
+	char *ep;
+	int base = 10;
+	if (*cp == '0') {
+		char c = *(cp + 1);
+		if (c == 'x' || c == 'X') {
+			base = 16;
+			cp += 2;
+		} else if (c >= '0' && c <= '7') {
+			base = 8;
+			cp++;
+		}
+	}
+	*result = simple_strtoul(cp, &ep, base);
+	if (cp == ep)
+		return TOMOYO_VALUE_TYPE_INVALID;
+	*str = ep;
+	switch (base) {
+	case 16:
+		return TOMOYO_VALUE_TYPE_HEXADECIMAL;
+	case 8:
+		return TOMOYO_VALUE_TYPE_OCTAL;
+	default:
+		return TOMOYO_VALUE_TYPE_DECIMAL;
+	}
+}
+
+/**
+ * tomoyo_print_ulong - Print an "unsigned long" value.
+ *
+ * @buffer:     Pointer to buffer.
+ * @buffer_len: Size of @buffer.
+ * @value:      An "unsigned long" value.
+ * @type:       Type of @value.
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+			const unsigned long value, const u8 type)
+{
+	if (type == TOMOYO_VALUE_TYPE_DECIMAL)
+		snprintf(buffer, buffer_len, "%lu", value);
+	else if (type == TOMOYO_VALUE_TYPE_OCTAL)
+		snprintf(buffer, buffer_len, "0%lo", value);
+	else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
+		snprintf(buffer, buffer_len, "0x%lX", value);
+	else
+		snprintf(buffer, buffer_len, "type(%u)", type);
+}
+
+/**
+ * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
+			     struct tomoyo_name_union *ptr)
+{
+	char *filename;
+	if (param->data[0] == '@') {
+		param->data++;
+		ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
+		return ptr->group != NULL;
+	}
+	filename = tomoyo_read_token(param);
+	if (!tomoyo_correct_word(filename))
+		return false;
+	ptr->filename = tomoyo_get_name(filename);
+	return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_number_union - Parse a tomoyo_number_union.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
+			       struct tomoyo_number_union *ptr)
+{
+	char *data;
+	u8 type;
+	unsigned long v;
+	memset(ptr, 0, sizeof(*ptr));
+	if (param->data[0] == '@') {
+		param->data++;
+		ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP);
+		return ptr->group != NULL;
+	}
+	data = tomoyo_read_token(param);
+	type = tomoyo_parse_ulong(&v, &data);
+	if (type == TOMOYO_VALUE_TYPE_INVALID)
+		return false;
+	ptr->values[0] = v;
+	ptr->value_type[0] = type;
+	if (!*data) {
+		ptr->values[1] = v;
+		ptr->value_type[1] = type;
+		return true;
+	}
+	if (*data++ != '-')
+		return false;
+	type = tomoyo_parse_ulong(&v, &data);
+	if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
+		return false;
+	ptr->values[1] = v;
+	ptr->value_type[1] = type;
+	return true;
+}
+
+/**
+ * tomoyo_byte_range - Check whether the string is a \ooo style octal value.
+ *
+ * @str: Pointer to the string.
+ *
+ * Returns true if @str is a \ooo style octal value, false otherwise.
+ *
+ * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
+ * This function verifies that \ooo is in valid range.
+ */
+static inline bool tomoyo_byte_range(const char *str)
+{
+	return *str >= '0' && *str++ <= '3' &&
+		*str >= '0' && *str++ <= '7' &&
+		*str >= '0' && *str <= '7';
+}
+
+/**
+ * tomoyo_alphabet_char - Check whether the character is an alphabet.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an alphabet character, false otherwise.
+ */
+static inline bool tomoyo_alphabet_char(const char c)
+{
+	return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+/**
+ * tomoyo_make_byte - Make byte value from three octal characters.
+ *
+ * @c1: The first character.
+ * @c2: The second character.
+ * @c3: The third character.
+ *
+ * Returns byte value.
+ */
+static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+{
+	return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+}
+
+/**
+ * tomoyo_valid - Check whether the character is a valid char.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is a valid character, false otherwise.
+ */
+static inline bool tomoyo_valid(const unsigned char c)
+{
+	return c > ' ' && c < 127;
+}
+
+/**
+ * tomoyo_invalid - Check whether the character is an invalid char.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an invalid character, false otherwise.
+ */
+static inline bool tomoyo_invalid(const unsigned char c)
+{
+	return c && (c <= ' ' || c >= 127);
+}
+
+/**
+ * tomoyo_str_starts - Check whether the given string starts with the given keyword.
+ *
+ * @src:  Pointer to pointer to the string.
+ * @find: Pointer to the keyword.
+ *
+ * Returns true if @src starts with @find, false otherwise.
+ *
+ * The @src is updated to point the first character after the @find
+ * if @src starts with @find.
+ */
+bool tomoyo_str_starts(char **src, const char *find)
+{
+	const int len = strlen(find);
+	char *tmp = *src;
+
+	if (strncmp(tmp, find, len))
+		return false;
+	tmp += len;
+	*src = tmp;
+	return true;
+}
+
+/**
+ * tomoyo_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ *
+ * Returns nothing.
+ */
+void tomoyo_normalize_line(unsigned char *buffer)
+{
+	unsigned char *sp = buffer;
+	unsigned char *dp = buffer;
+	bool first = true;
+
+	while (tomoyo_invalid(*sp))
+		sp++;
+	while (*sp) {
+		if (!first)
+			*dp++ = ' ';
+		first = false;
+		while (tomoyo_valid(*sp))
+			*dp++ = *sp++;
+		while (tomoyo_invalid(*sp))
+			sp++;
+	}
+	*dp = '\0';
+}
+
+/**
+ * tomoyo_correct_word2 - Validate a string.
+ *
+ * @string: The string to check. Maybe non-'\0'-terminated.
+ * @len:    Length of @string.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+static bool tomoyo_correct_word2(const char *string, size_t len)
+{
+	const char *const start = string;
+	bool in_repetition = false;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	if (!len)
+		goto out;
+	while (len--) {
+		c = *string++;
+		if (c == '\\') {
+			if (!len--)
+				goto out;
+			c = *string++;
+			switch (c) {
+			case '\\':  /* "\\" */
+				continue;
+			case '$':   /* "\$" */
+			case '+':   /* "\+" */
+			case '?':   /* "\?" */
+			case '*':   /* "\*" */
+			case '@':   /* "\@" */
+			case 'x':   /* "\x" */
+			case 'X':   /* "\X" */
+			case 'a':   /* "\a" */
+			case 'A':   /* "\A" */
+			case '-':   /* "\-" */
+				continue;
+			case '{':   /* "/\{" */
+				if (string - 3 < start || *(string - 3) != '/')
+					break;
+				in_repetition = true;
+				continue;
+			case '}':   /* "\}/" */
+				if (*string != '/')
+					break;
+				if (!in_repetition)
+					break;
+				in_repetition = false;
+				continue;
+			case '0':   /* "\ooo" */
+			case '1':
+			case '2':
+			case '3':
+				if (!len-- || !len--)
+					break;
+				d = *string++;
+				e = *string++;
+				if (d < '0' || d > '7' || e < '0' || e > '7')
+					break;
+				c = tomoyo_make_byte(c, d, e);
+				if (c <= ' ' || c >= 127)
+					continue;
+			}
+			goto out;
+		} else if (in_repetition && c == '/') {
+			goto out;
+		} else if (c <= ' ' || c >= 127) {
+			goto out;
+		}
+	}
+	if (in_repetition)
+		goto out;
+	return true;
+ out:
+	return false;
+}
+
+/**
+ * tomoyo_correct_word - Validate a string.
+ *
+ * @string: The string to check.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_word(const char *string)
+{
+	return tomoyo_correct_word2(string, strlen(string));
+}
+
+/**
+ * tomoyo_correct_path - Validate a pathname.
+ *
+ * @filename: The pathname to check.
+ *
+ * Check whether the given pathname follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_path(const char *filename)
+{
+	return *filename == '/' && tomoyo_correct_word(filename);
+}
+
+/**
+ * tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_correct_domain(const unsigned char *domainname)
+{
+	if (!domainname || !tomoyo_domain_def(domainname))
+		return false;
+	domainname = strchr(domainname, ' ');
+	if (!domainname++)
+		return true;
+	while (1) {
+		const unsigned char *cp = strchr(domainname, ' ');
+		if (!cp)
+			break;
+		if (*domainname != '/' ||
+		    !tomoyo_correct_word2(domainname, cp - domainname))
+			return false;
+		domainname = cp + 1;
+	}
+	return tomoyo_correct_path(domainname);
+}
+
+/**
+ * tomoyo_domain_def - Check whether the given token can be a domainname.
+ *
+ * @buffer: The token to check.
+ *
+ * Returns true if @buffer possibly be a domainname, false otherwise.
+ */
+bool tomoyo_domain_def(const unsigned char *buffer)
+{
+	const unsigned char *cp;
+	int len;
+	if (*buffer != '<')
+		return false;
+	cp = strchr(buffer, ' ');
+	if (!cp)
+		len = strlen(buffer);
+	else
+		len = cp - buffer;
+	if (buffer[len - 1] != '>' ||
+	    !tomoyo_correct_word2(buffer + 1, len - 2))
+		return false;
+	return true;
+}
+
+/**
+ * tomoyo_find_domain - Find a domain by the given name.
+ *
+ * @domainname: The domainname to find.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+{
+	struct tomoyo_domain_info *domain;
+	struct tomoyo_path_info name;
+
+	name.name = domainname;
+	tomoyo_fill_path_info(&name);
+	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+		if (!domain->is_deleted &&
+		    !tomoyo_pathcmp(&name, domain->domainname))
+			return domain;
+	}
+	return NULL;
+}
+
+/**
+ * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ *
+ * @filename: The string to evaluate.
+ *
+ * Returns the initial length without a pattern in @filename.
+ */
+static int tomoyo_const_part_length(const char *filename)
+{
+	char c;
+	int len = 0;
+
+	if (!filename)
+		return 0;
+	while ((c = *filename++) != '\0') {
+		if (c != '\\') {
+			len++;
+			continue;
+		}
+		c = *filename++;
+		switch (c) {
+		case '\\':  /* "\\" */
+			len += 2;
+			continue;
+		case '0':   /* "\ooo" */
+		case '1':
+		case '2':
+		case '3':
+			c = *filename++;
+			if (c < '0' || c > '7')
+				break;
+			c = *filename++;
+			if (c < '0' || c > '7')
+				break;
+			len += 4;
+			continue;
+		}
+		break;
+	}
+	return len;
+}
+
+/**
+ * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
+ *
+ * The caller sets "struct tomoyo_path_info"->name.
+ */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+{
+	const char *name = ptr->name;
+	const int len = strlen(name);
+
+	ptr->const_len = tomoyo_const_part_length(name);
+	ptr->is_dir = len && (name[len - 1] == '/');
+	ptr->is_patterned = (ptr->const_len < len);
+	ptr->hash = full_name_hash(name, len);
+}
+
+/**
+ * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern2(const char *filename,
+					 const char *filename_end,
+					 const char *pattern,
+					 const char *pattern_end)
+{
+	while (filename < filename_end && pattern < pattern_end) {
+		char c;
+		if (*pattern != '\\') {
+			if (*filename++ != *pattern++)
+				return false;
+			continue;
+		}
+		c = *filename;
+		pattern++;
+		switch (*pattern) {
+			int i;
+			int j;
+		case '?':
+			if (c == '/') {
+				return false;
+			} else if (c == '\\') {
+				if (filename[1] == '\\')
+					filename++;
+				else if (tomoyo_byte_range(filename + 1))
+					filename += 3;
+				else
+					return false;
+			}
+			break;
+		case '\\':
+			if (c != '\\')
+				return false;
+			if (*++filename != '\\')
+				return false;
+			break;
+		case '+':
+			if (!isdigit(c))
+				return false;
+			break;
+		case 'x':
+			if (!isxdigit(c))
+				return false;
+			break;
+		case 'a':
+			if (!tomoyo_alphabet_char(c))
+				return false;
+			break;
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+			if (c == '\\' && tomoyo_byte_range(filename + 1)
+			    && strncmp(filename + 1, pattern, 3) == 0) {
+				filename += 3;
+				pattern += 2;
+				break;
+			}
+			return false; /* Not matched. */
+		case '*':
+		case '@':
+			for (i = 0; i <= filename_end - filename; i++) {
+				if (tomoyo_file_matches_pattern2(
+						    filename + i, filename_end,
+						    pattern + 1, pattern_end))
+					return true;
+				c = filename[i];
+				if (c == '.' && *pattern == '@')
+					break;
+				if (c != '\\')
+					continue;
+				if (filename[i + 1] == '\\')
+					i++;
+				else if (tomoyo_byte_range(filename + i + 1))
+					i += 3;
+				else
+					break; /* Bad pattern. */
+			}
+			return false; /* Not matched. */
+		default:
+			j = 0;
+			c = *pattern;
+			if (c == '$') {
+				while (isdigit(filename[j]))
+					j++;
+			} else if (c == 'X') {
+				while (isxdigit(filename[j]))
+					j++;
+			} else if (c == 'A') {
+				while (tomoyo_alphabet_char(filename[j]))
+					j++;
+			}
+			for (i = 1; i <= j; i++) {
+				if (tomoyo_file_matches_pattern2(
+						    filename + i, filename_end,
+						    pattern + 1, pattern_end))
+					return true;
+			}
+			return false; /* Not matched or bad pattern. */
+		}
+		filename++;
+		pattern++;
+	}
+	while (*pattern == '\\' &&
+	       (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
+		pattern += 2;
+	return filename == filename_end && pattern == pattern_end;
+}
+
+/**
+ * tomoyo_file_matches_pattern - Pattern matching without '/' character.
+ *
+ * @filename:     The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern:      The start of pattern to compare.
+ * @pattern_end:  The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern(const char *filename,
+					const char *filename_end,
+					const char *pattern,
+					const char *pattern_end)
+{
+	const char *pattern_start = pattern;
+	bool first = true;
+	bool result;
+
+	while (pattern < pattern_end - 1) {
+		/* Split at "\-" pattern. */
+		if (*pattern++ != '\\' || *pattern++ != '-')
+			continue;
+		result = tomoyo_file_matches_pattern2(filename,
+						      filename_end,
+						      pattern_start,
+						      pattern - 2);
+		if (first)
+			result = !result;
+		if (result)
+			return false;
+		first = false;
+		pattern_start = pattern;
+	}
+	result = tomoyo_file_matches_pattern2(filename, filename_end,
+					      pattern_start, pattern_end);
+	return first ? result : !result;
+}
+
+/**
+ * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
+ *
+ * @f: The start of string to check.
+ * @p: The start of pattern to compare.
+ *
+ * Returns true if @f matches @p, false otherwise.
+ */
+static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
+{
+	const char *f_delimiter;
+	const char *p_delimiter;
+
+	while (*f && *p) {
+		f_delimiter = strchr(f, '/');
+		if (!f_delimiter)
+			f_delimiter = f + strlen(f);
+		p_delimiter = strchr(p, '/');
+		if (!p_delimiter)
+			p_delimiter = p + strlen(p);
+		if (*p == '\\' && *(p + 1) == '{')
+			goto recursive;
+		if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
+						 p_delimiter))
+			return false;
+		f = f_delimiter;
+		if (*f)
+			f++;
+		p = p_delimiter;
+		if (*p)
+			p++;
+	}
+	/* Ignore trailing "\*" and "\@" in @pattern. */
+	while (*p == '\\' &&
+	       (*(p + 1) == '*' || *(p + 1) == '@'))
+		p += 2;
+	return !*f && !*p;
+ recursive:
+	/*
+	 * The "\{" pattern is permitted only after '/' character.
+	 * This guarantees that below "*(p - 1)" is safe.
+	 * Also, the "\}" pattern is permitted only before '/' character
+	 * so that "\{" + "\}" pair will not break the "\-" operator.
+	 */
+	if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
+	    *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
+		return false; /* Bad pattern. */
+	do {
+		/* Compare current component with pattern. */
+		if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
+						 p_delimiter - 2))
+			break;
+		/* Proceed to next component. */
+		f = f_delimiter;
+		if (!*f)
+			break;
+		f++;
+		/* Continue comparison. */
+		if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
+			return true;
+		f_delimiter = strchr(f, '/');
+	} while (f_delimiter);
+	return false; /* Not matched. */
+}
+
+/**
+ * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
+ *
+ * @filename: The filename to check.
+ * @pattern:  The pattern to compare.
+ *
+ * Returns true if matches, false otherwise.
+ *
+ * The following patterns are available.
+ *   \\     \ itself.
+ *   \ooo   Octal representation of a byte.
+ *   \*     Zero or more repetitions of characters other than '/'.
+ *   \@     Zero or more repetitions of characters other than '/' or '.'.
+ *   \?     1 byte character other than '/'.
+ *   \$     One or more repetitions of decimal digits.
+ *   \+     1 decimal digit.
+ *   \X     One or more repetitions of hexadecimal digits.
+ *   \x     1 hexadecimal digit.
+ *   \A     One or more repetitions of alphabet characters.
+ *   \a     1 alphabet character.
+ *
+ *   \-     Subtraction operator.
+ *
+ *   /\{dir\}/   '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
+ *               /dir/dir/dir/ ).
+ */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+				 const struct tomoyo_path_info *pattern)
+{
+	const char *f = filename->name;
+	const char *p = pattern->name;
+	const int len = pattern->const_len;
+
+	/* If @pattern doesn't contain pattern, I can use strcmp(). */
+	if (!pattern->is_patterned)
+		return !tomoyo_pathcmp(filename, pattern);
+	/* Don't compare directory and non-directory. */
+	if (filename->is_dir != pattern->is_dir)
+		return false;
+	/* Compare the initial length without patterns. */
+	if (strncmp(f, p, len))
+		return false;
+	f += len;
+	p += len;
+	return tomoyo_path_matches_pattern2(f, p);
+}
+
+/**
+ * tomoyo_get_exe - Get tomoyo_realpath() of current process.
+ *
+ * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so the caller must call kfree()
+ * if this function didn't return NULL.
+ */
+const char *tomoyo_get_exe(void)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	const char *cp = NULL;
+
+	if (!mm)
+		return NULL;
+	down_read(&mm->mmap_sem);
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
+			cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
+			break;
+		}
+	}
+	up_read(&mm->mmap_sem);
+	return cp;
+}
+
+/**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @ns:      Pointer to "struct tomoyo_policy_namespace".
+ * @profile: Profile number.
+ * @index:   Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
+		    const u8 index)
+{
+	u8 mode;
+	struct tomoyo_profile *p;
+
+	if (!tomoyo_policy_loaded)
+		return TOMOYO_CONFIG_DISABLED;
+	p = tomoyo_profile(ns, profile);
+	mode = p->config[index];
+	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+		mode = p->config[tomoyo_index2category[index]
+				 + TOMOYO_MAX_MAC_INDEX];
+	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+		mode = p->default_config;
+	return mode & 3;
+}
+
+/**
+ * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
+ *
+ * @r:      Pointer to "struct tomoyo_request_info" to initialize.
+ * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index:  Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+			     struct tomoyo_domain_info *domain, const u8 index)
+{
+	u8 profile;
+	memset(r, 0, sizeof(*r));
+	if (!domain)
+		domain = tomoyo_domain();
+	r->domain = domain;
+	profile = domain->profile;
+	r->profile = profile;
+	r->type = index;
+	r->mode = tomoyo_get_mode(domain->ns, profile, index);
+	return r->mode;
+}
+
+/**
+ * tomoyo_domain_quota_is_ok - Check for domain's quota.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
+{
+	unsigned int count = 0;
+	struct tomoyo_domain_info *domain = r->domain;
+	struct tomoyo_acl_info *ptr;
+
+	if (r->mode != TOMOYO_CONFIG_LEARNING)
+		return false;
+	if (!domain)
+		return true;
+	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+		u16 perm;
+		u8 i;
+		if (ptr->is_deleted)
+			continue;
+		switch (ptr->type) {
+		case TOMOYO_TYPE_PATH_ACL:
+			perm = container_of(ptr, struct tomoyo_path_acl, head)
+				->perm;
+			break;
+		case TOMOYO_TYPE_PATH2_ACL:
+			perm = container_of(ptr, struct tomoyo_path2_acl, head)
+				->perm;
+			break;
+		case TOMOYO_TYPE_PATH_NUMBER_ACL:
+			perm = container_of(ptr, struct tomoyo_path_number_acl,
+					    head)->perm;
+			break;
+		case TOMOYO_TYPE_MKDEV_ACL:
+			perm = container_of(ptr, struct tomoyo_mkdev_acl,
+					    head)->perm;
+			break;
+		case TOMOYO_TYPE_INET_ACL:
+			perm = container_of(ptr, struct tomoyo_inet_acl,
+					    head)->perm;
+			break;
+		case TOMOYO_TYPE_UNIX_ACL:
+			perm = container_of(ptr, struct tomoyo_unix_acl,
+					    head)->perm;
+			break;
+		case TOMOYO_TYPE_MANUAL_TASK_ACL:
+			perm = 0;
+			break;
+		default:
+			perm = 1;
+		}
+		for (i = 0; i < 16; i++)
+			if (perm & (1 << i))
+				count++;
+	}
+	if (count < tomoyo_profile(domain->ns, domain->profile)->
+	    pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
+		return true;
+	if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) {
+		domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true;
+		/* r->granted = false; */
+		tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
+		printk(KERN_WARNING "WARNING: "
+		       "Domain '%s' has too many ACLs to hold. "
+		       "Stopped learning mode.\n", domain->domainname->name);
+	}
+	return false;
+}