/**
  * 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 u8 profile, const u8 index,
+static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
+                            const u8 profile, const u8 index,
                             const bool is_granted)
 {
        u8 mode;
        struct tomoyo_profile *p;
        if (!tomoyo_policy_loaded)
                return false;
-       p = tomoyo_profile(profile);
+       p = tomoyo_profile(ns, profile);
        if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
                return false;
        mode = p->config[index];
        char *buf;
        struct tomoyo_log *entry;
        bool quota_exceeded = false;
-       if (!tomoyo_get_audit(r->profile, r->type, r->granted))
+       if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted))
                goto out;
        buf = tomoyo_init_log(r, len, fmt, args);
        if (!buf)
 
 #include <linux/security.h>
 #include "common.h"
 
-/* Profile version. Currently only 20090903 is defined. */
-static unsigned int tomoyo_profile_version;
-
-/* Profile table. Memory is allocated as needed. */
-static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
-
 /* String table for operation mode. */
 const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
        [TOMOYO_CONFIG_DISABLED]   = "disabled",
        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 = 20100903;
+       tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
+       list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
+}
+
+/**
+ * tomoyo_print_namespace - Print namespace header.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
+{
+       if (!tomoyo_namespace_enabled)
+               return;
+       tomoyo_set_string(head,
+                         container_of(head->r.ns,
+                                      struct tomoyo_policy_namespace,
+                                      namespace_list)->name);
+       tomoyo_set_space(head);
+}
+
 /**
  * tomoyo_print_name_union - Print a tomoyo_name_union.
  *
 /**
  * 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(const unsigned int profile)
+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 = tomoyo_profile_ptr[profile];
+       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 = tomoyo_profile_ptr[profile];
+       ptr = ns->profile_ptr[profile];
        if (!ptr && tomoyo_memory_ok(entry)) {
                ptr = entry;
                ptr->default_config = TOMOYO_CONFIG_DISABLED |
                ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024;
                ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048;
                mb(); /* Avoid out-of-order execution. */
-               tomoyo_profile_ptr[profile] = ptr;
+               ns->profile_ptr[profile] = ptr;
                entry = NULL;
        }
        mutex_unlock(&tomoyo_policy_lock);
 /**
  * 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 u8 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 = tomoyo_profile_ptr[profile];
+       struct tomoyo_profile *ptr = ns->profile_ptr[profile];
        if (!ptr)
                ptr = &tomoyo_null_profile;
        return ptr;
        unsigned int i;
        char *cp;
        struct tomoyo_profile *profile;
-       if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+       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(i);
+       profile = tomoyo_assign_profile(head->w.ns, i);
        if (!profile)
                return -EINVAL;
        cp = strchr(data, '=');
 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 = tomoyo_profile_ptr[index];
+       profile = ns->profile_ptr[index];
        switch (head->r.step) {
        case 0:
-               tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", 20090903);
+               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 (tomoyo_profile_ptr[head->r.index])
+                       if (ns->profile_ptr[head->r.index])
                                break;
                if (head->r.index == TOMOYO_MAX_PROFILES)
                        return;
                        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);
                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;
                        const u8 config = profile->config[i];
                        if (config == TOMOYO_CONFIG_USE_DEFAULT)
                                continue;
+                       tomoyo_print_namespace(head);
                        tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::",
                                         tomoyo_mac_keywords[i]);
                        tomoyo_print_config(head, config);
 {
        struct tomoyo_manager e = { };
        struct tomoyo_acl_param param = {
+               /* .ns = &tomoyo_kernel_namespace, */
                .is_delete = is_delete,
-               .list = &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+               .list = &tomoyo_kernel_namespace.
+               policy_list[TOMOYO_ID_MANAGER],
        };
        int error = is_delete ? -ENOENT : -ENOMEM;
        if (tomoyo_domain_def(manager)) {
 static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
-       bool is_delete = tomoyo_str_starts(&data, "delete ");
 
        if (!strcmp(data, "manage_by_non_root")) {
-               tomoyo_manage_by_non_root = !is_delete;
+               tomoyo_manage_by_non_root = !head->w.is_delete;
                return 0;
        }
-       return tomoyo_update_manager_entry(data, is_delete);
+       return tomoyo_update_manager_entry(data, head->w.is_delete);
 }
 
 /**
 {
        if (head->r.eof)
                return;
-       list_for_each_cookie(head->r.acl,
-                            &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+       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)
                return true;
        if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
-                               head.list) {
+       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;
        exe = tomoyo_get_exe();
        if (!exe)
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
-                               head.list) {
+       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;
 }
 
 /**
- * tomoyo_select_one - Parse select command.
+ * tomoyo_select_domain - Parse select command.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  * @data: String to parse.
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
+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 (!strcmp(data, "allow_execute")) {
-               head->r.print_execute_only = true;
-               return true;
-       }
+       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;
 /**
  * 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.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_domain2(struct list_head *list, char *data,
+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 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;
-       bool is_delete = false;
-       bool is_select = false;
+       const bool is_delete = head->w.is_delete;
+       bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
        unsigned int profile;
-
-       if (tomoyo_str_starts(&data, "delete "))
-               is_delete = true;
-       else if (tomoyo_str_starts(&data, "select "))
-               is_select = true;
-       if (is_select && tomoyo_select_one(head, data))
-               return 0;
-       /* Don't allow updating policies by non manager programs. */
-       if (!tomoyo_manager())
-               return -EPERM;
-       if (tomoyo_domain_def(data)) {
+       if (*data == '<') {
                domain = NULL;
                if (is_delete)
                        tomoyo_delete_domain(data);
                else if (is_select)
                        domain = tomoyo_find_domain(data);
                else
-                       domain = tomoyo_assign_domain(data, 0);
+                       domain = tomoyo_assign_domain(data, false);
                head->w.domain = domain;
                return 0;
        }
        if (!domain)
                return -EINVAL;
-
+       ns = domain->ns;
        if (sscanf(data, "use_profile %u", &profile) == 1
            && profile < TOMOYO_MAX_PROFILES) {
-               if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
+               if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
                        domain->profile = (u8) profile;
                return 0;
        }
                domain->transition_failed = !is_delete;
                return 0;
        }
-       return tomoyo_write_domain2(&domain->acl_info_list, data, is_delete);
+       return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
+                                   is_delete);
 }
 
 /**
 static void tomoyo_set_group(struct tomoyo_io_buffer *head,
                             const char *category)
 {
-       if (head->type == TOMOYO_EXCEPTIONPOLICY)
+       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);
 }
 
                for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
                        if (!(perm & (1 << bit)))
                                continue;
-                       if (head->r.print_execute_only &&
+                       if (head->r.print_transition_related_only &&
                            bit != TOMOYO_TYPE_EXECUTE)
                                continue;
                        if (first) {
                if (first)
                        return true;
                tomoyo_print_name_union(head, &ptr->name);
-       } else if (head->r.print_execute_only) {
+       } else if (head->r.print_transition_related_only) {
                return true;
        } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
                struct tomoyo_path2_acl *ptr =
        domain = tomoyo_find_domain(cp + 1);
        if (strict_strtoul(data, 10, &profile))
                return -EINVAL;
-       if (domain && profile < TOMOYO_MAX_PROFILES
-           && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+       if (domain && (!tomoyo_policy_loaded ||
+                      head->w.ns->profile_ptr[(u8) profile]))
                domain->profile = (u8) profile;
        return 0;
 }
 }
 
 static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
-       [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",
+       [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 ",
 };
 
 static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
  */
 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;
-       param.is_delete = tomoyo_str_starts(¶m.data, "delete ");
-       if (!param.is_delete && tomoyo_str_starts(¶m.data, "select ") &&
-           !strcmp(param.data, "execute_only")) {
-               head->r.print_execute_only = true;
-               return 0;
-       }
-       /* Don't allow updating policies by non manager programs. */
-       if (!tomoyo_manager())
-               return -EPERM;
        if (tomoyo_str_starts(¶m.data, "aggregator "))
                return tomoyo_write_aggregator(¶m);
        for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
                char *data;
                group = simple_strtoul(param.data, &data, 10);
                if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
-                       return tomoyo_write_domain2(&tomoyo_acl_group[group],
-                                                   data, param.is_delete);
+                       return tomoyo_write_domain2
+                               (head->w.ns, &head->w.ns->acl_group[group],
+                                data, is_delete);
        }
        return -EINVAL;
 }
  */
 static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
 {
-       list_for_each_cookie(head->r.group, &tomoyo_group_list[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) {
                                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) {
  */
 static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
 {
-       list_for_each_cookie(head->r.acl, &tomoyo_policy_list[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)
                        {
                                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 ?
                        {
                                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);
  */
 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_MAX_ACL_GROUPS) {
                head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY
                        - TOMOYO_MAX_GROUP;
-               if (!tomoyo_read_domain2(head, &tomoyo_acl_group
+               if (!tomoyo_read_domain2(head, &ns->acl_group
                                         [head->r.acl_group_index]))
                        return;
                head->r.step++;
                return;
        snprintf(buffer, len - 1, "%s", cp);
        tomoyo_normalize_line(buffer);
-       tomoyo_write_domain2(&domain->acl_info_list, buffer, false);
+       tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
+                            false);
        kfree(buffer);
 }
 
        return head->poll(file, wait);
 }
 
+/**
+ * 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->read_user_buf_avail = buffer_len;
        if (tomoyo_flush(head))
                /* Call the policy handler. */
-               head->read(head);
-       tomoyo_flush(head);
+               do {
+                       tomoyo_set_namespace_cursor(head);
+                       head->read(head);
+               } while (tomoyo_flush(head) &&
+                        tomoyo_has_more_namespace(head));
        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.
  *
                         const char __user *buffer, const int buffer_len)
 {
        int error = buffer_len;
-       int avail_len = buffer_len;
+       size_t avail_len = buffer_len;
        char *cp0 = head->write_buf;
-
        if (!head->write)
                return -ENOSYS;
        if (!access_ok(VERIFY_READ, buffer, buffer_len))
                return -EFAULT;
-       /* Don't allow updating policies by non manager programs. */
-       if (head->write != tomoyo_write_pid &&
-           head->write != tomoyo_write_domain &&
-           head->write != tomoyo_write_exception && !tomoyo_manager())
-               return -EPERM;
        if (mutex_lock_interruptible(&head->io_sem))
                return -EINTR;
        /* Read a line and dispatch it to the policy handler. */
        while (avail_len > 0) {
                char c;
                if (head->w.avail >= head->writebuf_size - 1) {
-                       error = -ENOMEM;
-                       break;
-               } else if (get_user(c, buffer)) {
+                       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;
                }
                cp0[head->w.avail - 1] = '\0';
                head->w.avail = 0;
                tomoyo_normalize_line(cp0);
-               head->write(head);
+               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;
+               }
        }
+out:
        mutex_unlock(&head->io_sem);
        return error;
 }
        struct tomoyo_domain_info *domain;
        const int idx = tomoyo_read_lock();
        tomoyo_policy_loaded = true;
-       /* Check all profiles currently assigned to domains are defined. */
+       printk(KERN_INFO "TOMOYO: 2.4.0\n");
        list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
                const u8 profile = domain->profile;
-               if (tomoyo_profile_ptr[profile])
+               const struct tomoyo_policy_namespace *ns = domain->ns;
+               if (ns->profile_version != 20100903)
+                       printk(KERN_ERR
+                              "Profile version %u is not supported.\n",
+                              ns->profile_version);
+               else if (!ns->profile_ptr[profile])
+                       printk(KERN_ERR
+                              "Profile %u (used by '%s') is not defined.\n",
+                              profile, domain->domainname->name);
+               else
                        continue;
-               printk(KERN_ERR "You need to define profile %u before using it.\n",
-                      profile);
-               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
+               printk(KERN_ERR
+                      "Userland tools for TOMOYO 2.4 must be installed and "
+                      "policy must be initialized.\n");
+               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ "
                       "for more information.\n");
-               panic("Profile %u (used by '%s') not defined.\n",
-                     profile, domain->domainname->name);
+               panic("STOP!");
        }
        tomoyo_read_unlock(idx);
-       if (tomoyo_profile_version != 20090903) {
-               printk(KERN_ERR "You need to install userland programs for "
-                      "TOMOYO 2.3 and initialize policy configuration.\n");
-               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
-                      "for more information.\n");
-               panic("Profile version %u is not supported.\n",
-                     tomoyo_profile_version);
-       }
-       printk(KERN_INFO "TOMOYO: 2.3.0\n");
        printk(KERN_INFO "Mandatory Access Control activated.\n");
 }
 
        TOMOYO_MAX_GROUP
 };
 
-/* A domain definition starts with <kernel>. */
-#define TOMOYO_ROOT_NAME                         "<kernel>"
-#define TOMOYO_ROOT_NAME_LEN                     (sizeof(TOMOYO_ROOT_NAME) - 1)
-
 /* Index numbers for type of numeric values. */
 enum tomoyo_value_type {
        TOMOYO_VALUE_TYPE_INVALID,
 /* 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,
        atomic_t users;
 } __packed;
 
+struct tomoyo_policy_namespace;
+
 /* Structure for request info. */
 struct tomoyo_request_info {
        struct tomoyo_domain_info *domain;
        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.           */
 struct tomoyo_acl_param {
        char *data;
        struct list_head *list;
+       struct tomoyo_policy_namespace *ns;
        bool is_delete;
 };
 
        char __user *read_user_buf;
        int read_user_buf_avail;
        struct {
+               struct list_head *ns;
                struct list_head *domain;
                struct list_head *group;
                struct list_head *acl;
                u8 w_pos;
                bool eof;
                bool print_this_domain_only;
-               bool print_execute_only;
+               bool print_transition_related_only;
                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.         */
                int avail;
+               bool is_delete;
        } w;
        /* Buffer for reading.                  */
        char *read_buf;
        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 20100903 is defined. */
+       unsigned int profile_version;
+       /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
+       const char *name;
+};
+
 /********** Function prototypes. **********/
 
+void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
 bool tomoyo_str_starts(char **src, const char *find);
 const char *tomoyo_get_exe(void);
 void tomoyo_normalize_line(unsigned char *buffer);
                          const struct tomoyo_name_union *ptr);
 bool tomoyo_compare_number_union(const unsigned long value,
                                 const struct tomoyo_number_union *ptr);
-int tomoyo_get_mode(const u8 profile, const u8 index);
+int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
+                   const u8 index);
 void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
        __attribute__ ((format(printf, 2, 3)));
 bool tomoyo_correct_domain(const unsigned char *domainname);
      __attribute__ ((format(printf, 2, 3)));
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
-                                               const u8 profile);
-struct tomoyo_profile *tomoyo_profile(const u8 profile);
+                                               const bool transit);
+struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
+                                     const u8 profile);
+struct tomoyo_policy_namespace *tomoyo_assign_namespace
+(const char *domainname);
 struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
                                      const u8 idx);
 unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
 bool tomoyo_permstr(const char *string, const char *keyword);
 
 const char *tomoyo_yesno(const unsigned int value);
+void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
+       __attribute__ ((format(printf, 2, 3)));
 void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
                       va_list args);
 void tomoyo_read_log(struct tomoyo_io_buffer *head);
 /* The list for "struct tomoyo_domain_info". */
 extern struct list_head tomoyo_domain_list;
 
-extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
-extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
 extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
 
 /* Lock for protecting policy. */
 /* Has /sbin/init started? */
 extern bool tomoyo_policy_loaded;
 
-extern struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];
-
 /* The kernel's domain. */
 extern struct tomoyo_domain_info tomoyo_kernel_domain;
+extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
+extern struct list_head tomoyo_namespace_list;
 
 extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
 extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
                a->value_type[1] == b->value_type[1];
 }
 
+/**
+ * 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)
 
 /**
 
 
 /* Variables definitions.*/
 
-/* The global ACL referred by "use_group" keyword. */
-struct list_head tomoyo_acl_group[TOMOYO_MAX_ACL_GROUPS];
-
 /* The initial domain. */
 struct tomoyo_domain_info tomoyo_kernel_domain;
 
        }
        if (!retried) {
                retried = true;
-               list = &tomoyo_acl_group[domain->group];
+               list = &domain->ns->acl_group[domain->group];
                goto retry;
        }
        r->granted = false;
 /* The list for "struct tomoyo_domain_info". */
 LIST_HEAD(tomoyo_domain_list);
 
-struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
-struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
-
 /**
  * tomoyo_last_word - Get last component of a domainname.
  *
- * @domainname: Domainname to check.
+ * @name: Domainname to check.
  *
  * Returns the last word of @domainname.
  */
                if (!e.domainname)
                        goto out;
        }
-       param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL];
+       param->list = ¶m->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
        error = tomoyo_update_policy(&e.head, sizeof(e), param,
                                     tomoyo_same_transition_control);
 out:
 }
 
 /**
- * tomoyo_transition_type - Get domain transition type.
+ * tomoyo_scan_transition - Try to find specific domain transition type.
  *
- * @domainname: The name of domain.
- * @program:    The name of program.
+ * @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 TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
- * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
- * @program suppresses domain transition, others otherwise.
+ * Returns true if found one, false otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
-                                const struct tomoyo_path_info *program)
+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;
-       const char *last_name = tomoyo_last_word(domainname->name);
-       u8 type;
-       for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
- next:
-               list_for_each_entry_rcu(ptr, &tomoyo_policy_list
-                                       [TOMOYO_ID_TRANSITION_CONTROL],
-                                       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;
-                       if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
+       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 {
                                /*
-                                * Do not check for initialize_domain if
-                                * no_initialize_domain matched.
+                                * Use direct strcmp() since this is
+                                * unlikely used.
                                 */
-                               type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
-                               goto next;
+                               if (strcmp(ptr->domainname->name, last_name))
+                                       continue;
                        }
-                       goto done;
                }
+               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++;
        }
- done:
        return type;
 }
 
        if (!e.original_name || !e.aggregated_name ||
            e.aggregated_name->is_patterned) /* No patterns allowed. */
                goto out;
-       param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR];
+       param->list = ¶m->ns->policy_list[TOMOYO_ID_AGGREGATOR];
        error = tomoyo_update_policy(&e.head, sizeof(e), param,
                                     tomoyo_same_aggregator);
 out:
 }
 
 /**
- * tomoyo_assign_domain - Create a domain.
+ * tomoyo_find_namespace - Find specified namespace.
  *
- * @domainname: The name of domain.
- * @profile:    Profile number to assign if the domain was newly created.
+ * @name: Name of namespace to find.
+ * @len:  Length of @name.
  *
- * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
+ * Returns pointer to "struct tomoyo_policy_namespace" if found,
+ * NULL otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
-                                               const u8 profile)
+static struct tomoyo_policy_namespace *tomoyo_find_namespace
+(const char *name, const unsigned int len)
 {
-       struct tomoyo_domain_info *entry;
-       struct tomoyo_domain_info *domain = NULL;
-       const struct tomoyo_path_info *saved_domainname;
-       bool found = false;
+       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;
+}
 
-       if (!tomoyo_correct_domain(domainname))
+/**
+ * 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;
-       saved_domainname = tomoyo_get_name(domainname);
-       if (!saved_domainname)
+       entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
+       if (!entry)
                return NULL;
-       entry = kzalloc(sizeof(*entry), GFP_NOFS);
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                goto out;
-       list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-               if (domain->is_deleted ||
-                   tomoyo_pathcmp(saved_domainname, domain->domainname))
-                       continue;
-               found = true;
-               break;
-       }
-       if (!found && tomoyo_memory_ok(entry)) {
-               INIT_LIST_HEAD(&entry->acl_info_list);
-               entry->domainname = saved_domainname;
-               saved_domainname = NULL;
-               entry->profile = profile;
-               list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
-               domain = entry;
+       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;
-               found = true;
        }
        mutex_unlock(&tomoyo_policy_lock);
- out:
-       tomoyo_put_name(saved_domainname);
+out:
        kfree(entry);
-       return found ? domain : NULL;
+       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 (!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);
+               }
+       }
+       return entry;
 }
 
 /**
        bool is_enforce;
        int retval = -ENOMEM;
        bool need_kfree = false;
+       bool reject_on_transition_failure = false;
        struct tomoyo_path_info rn = { }; /* real name */
 
        mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
        /* Check 'aggregator' directive. */
        {
                struct tomoyo_aggregator *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_policy_list
-                                       [TOMOYO_ID_AGGREGATOR], head.list) {
+               struct list_head *list =
+                       &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
+               /* Check 'aggregator' directive. */
+               list_for_each_entry_rcu(ptr, list, head.list) {
                        if (ptr->head.is_deleted ||
                            !tomoyo_path_matches_pattern(&rn,
                                                         ptr->original_name))
        }
 
        /* Calculate domain to transit to. */
-       switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
+       switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
+                                      &rn)) {
+       case TOMOYO_TRANSITION_CONTROL_RESET:
+               /* Transit to the root of specified namespace. */
+               snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
+               /*
+                * Make do_execve() fail if domain transition across namespaces
+                * has failed.
+                */
+               reject_on_transition_failure = true;
+               break;
        case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
-               /* Transit to the child of tomoyo_kernel_domain domain. */
-               snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
-                        "%s", rn.name);
+               /* Transit to the child of current namespace's root. */
+               snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+                        old_domain->ns->name, rn.name);
                break;
        case TOMOYO_TRANSITION_CONTROL_KEEP:
                /* Keep current domain. */
                }
                break;
        }
-       if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
-               goto done;
-       domain = tomoyo_find_domain(tmp);
        if (!domain)
-               domain = tomoyo_assign_domain(tmp, old_domain->profile);
- done:
+               domain = tomoyo_assign_domain(tmp, true);
        if (domain)
-               goto out;
-       printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
-       if (is_enforce)
-               retval = -EPERM;
-       else
-               old_domain->transition_failed = true;
+               retval = 0;
+       else if (reject_on_transition_failure) {
+               printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n", tmp);
+               retval = -ENOMEM;
+       } else if (r.mode == TOMOYO_CONFIG_ENFORCING)
+               retval = -ENOMEM;
+       else {
+               retval = 0;
+               if (!old_domain->transition_failed) {
+                       old_domain->transition_failed = true;
+                       r.granted = false;
+                       tomoyo_write_log(&r, "%s", "transition_failed\n");
+                       printk(KERN_WARNING
+                              "ERROR: Domain '%s' not defined.\n", tmp);
+               }
+       }
  out:
        if (!domain)
                domain = old_domain;
 
        int error;
 
        r->type = tomoyo_p2mac[operation];
-       r->mode = tomoyo_get_mode(r->profile, r->type);
+       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;
 
 static void tomoyo_collect_entry(void)
 {
        int i;
+       enum tomoyo_policy_id id;
+       struct tomoyo_policy_namespace *ns;
+       int idx;
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return;
-       for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
-               if (!tomoyo_collect_member(i, &tomoyo_policy_list[i]))
-                       goto unlock;
-       }
-       for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
-               if (!tomoyo_collect_acl(&tomoyo_acl_group[i]))
-                       goto unlock;
+       idx = tomoyo_read_lock();
        {
                struct tomoyo_domain_info *domain;
                list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
                                goto unlock;
                }
        }
-       for (i = 0; i < TOMOYO_MAX_HASH; i++) {
-               struct tomoyo_name *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], head.list) {
-                       if (atomic_read(&ptr->head.users))
-                               continue;
-                       if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->head.list))
+       list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) {
+               for (id = 0; id < TOMOYO_MAX_POLICY; id++)
+                       if (!tomoyo_collect_member(id, &ns->policy_list[id]))
                                goto unlock;
+               for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
+                       if (!tomoyo_collect_acl(&ns->acl_group[i]))
+                               goto unlock;
+               for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
+                       struct list_head *list = &ns->group_list[i];
+                       struct tomoyo_group *group;
+                       switch (i) {
+                       case 0:
+                               id = TOMOYO_ID_PATH_GROUP;
+                               break;
+                       default:
+                               id = TOMOYO_ID_NUMBER_GROUP;
+                               break;
+                       }
+                       list_for_each_entry(group, list, head.list) {
+                               if (!tomoyo_collect_member
+                                   (id, &group->member_list))
+                                       goto unlock;
+                               if (!list_empty(&group->member_list) ||
+                                   atomic_read(&group->head.users))
+                                       continue;
+                               if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
+                                                     &group->head.list))
+                                       goto unlock;
+                       }
                }
        }
-       for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
-               struct list_head *list = &tomoyo_group_list[i];
-               int id;
-               struct tomoyo_group *group;
-               switch (i) {
-               case 0:
-                       id = TOMOYO_ID_PATH_GROUP;
-                       break;
-               default:
-                       id = TOMOYO_ID_NUMBER_GROUP;
-                       break;
-               }
-               list_for_each_entry(group, list, head.list) {
-                       if (!tomoyo_collect_member(id, &group->member_list))
-                               goto unlock;
-                       if (!list_empty(&group->member_list) ||
-                           atomic_read(&group->head.users))
+       for (i = 0; i < TOMOYO_MAX_HASH; i++) {
+               struct list_head *list = &tomoyo_name_list[i];
+               struct tomoyo_shared_acl_head *ptr;
+               list_for_each_entry(ptr, list, list) {
+                       if (atomic_read(&ptr->users))
                                continue;
-                       if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
-                                             &group->head.list))
+                       if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
                                goto unlock;
                }
        }
- unlock:
+unlock:
+       tomoyo_read_unlock(idx);
        mutex_unlock(&tomoyo_policy_lock);
 }
 
 
                return NULL;
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                goto out;
-       list = &tomoyo_group_list[idx];
+       list = ¶m->ns->group_list[idx];
        list_for_each_entry(group, list, head.list) {
                if (e.group_name != group->group_name)
                        continue;
        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_POLICY; idx++)
-               INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
-       for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
-               INIT_LIST_HEAD(&tomoyo_group_list[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);
-       for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
-               INIT_LIST_HEAD(&tomoyo_acl_group[idx]);
-       tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
+       tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>");
        list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-       idx = tomoyo_read_lock();
-       if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
-               panic("Can't register tomoyo_kernel_domain");
 #if 0
        /* Will be replaced with tomoyo_load_builtin_policy(). */
        {
                                        TOMOYO_TRANSITION_CONTROL_INITIALIZE);
        }
 #endif
-       tomoyo_read_unlock(idx);
 }
 
 
 
  */
 bool tomoyo_correct_domain(const unsigned char *domainname)
 {
-       if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
-                                  TOMOYO_ROOT_NAME_LEN))
-               goto out;
-       domainname += TOMOYO_ROOT_NAME_LEN;
-       if (!*domainname)
+       if (!domainname || !tomoyo_domain_def(domainname))
+               return false;
+       domainname = strchr(domainname, ' ');
+       if (!domainname++)
                return true;
-       if (*domainname++ != ' ')
-               goto out;
        while (1) {
                const unsigned char *cp = strchr(domainname, ' ');
                if (!cp)
                        break;
                if (*domainname != '/' ||
                    !tomoyo_correct_word2(domainname, cp - domainname))
-                       goto out;
+                       return false;
                domainname = cp + 1;
        }
        return tomoyo_correct_path(domainname);
- out:
-       return false;
 }
 
 /**
  */
 bool tomoyo_domain_def(const unsigned char *buffer)
 {
-       return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+       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_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 u8 profile, const u8 index)
+int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
+                   const u8 index)
 {
        u8 mode;
        const u8 category = TOMOYO_MAC_CATEGORY_FILE;
        if (!tomoyo_policy_loaded)
                return TOMOYO_CONFIG_DISABLED;
-       mode = tomoyo_profile(profile)->config[index];
+       mode = tomoyo_profile(ns, profile)->config[index];
        if (mode == TOMOYO_CONFIG_USE_DEFAULT)
-               mode = tomoyo_profile(profile)->config[category];
+               mode = tomoyo_profile(ns, profile)->config[category];
        if (mode == TOMOYO_CONFIG_USE_DEFAULT)
-               mode = tomoyo_profile(profile)->default_config;
+               mode = tomoyo_profile(ns, profile)->default_config;
        return mode & 3;
 }
 
        profile = domain->profile;
        r->profile = profile;
        r->type = index;
-       r->mode = tomoyo_get_mode(profile, index);
+       r->mode = tomoyo_get_mode(domain->ns, profile, index);
        return r->mode;
 }
 
-/**
- * tomoyo_last_word - Get last component of a line.
- *
- * @line: A line.
- *
- * Returns the last word of a line.
- */
-const char *tomoyo_last_word(const char *name)
-{
-       const char *cp = strrchr(name, ' ');
-       if (cp)
-               return cp + 1;
-       return name;
-}
-
 /**
  * tomoyo_domain_quota_is_ok - Check for domain's quota.
  *
                        if (perm & (1 << i))
                                count++;
        }
-       if (count < tomoyo_profile(domain->profile)->
+       if (count < tomoyo_profile(domain->ns, domain->profile)->
            pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
                return true;
        if (!domain->quota_warned) {