This is the main part for domain transition.
In TOMOYO Linux, domains are automatically created at runtime.

To make discussion smooth by reducing the amount of patches,
we pruned argv[0] checks (although we referred the need of argv[0] checking
at AppArmor's thread, http://lkml.org/lkml/2007/5/26/52 ).

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>

---------------
security/tomoyo/domain.c |  782 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 782 insertions(+)

diff -ubBpErN linux-2.6.21.5/security/tomoyo/domain.c 
linux-2.6.21.5-tomoyo/security/tomoyo/domain.c
--- linux-2.6.21.5/security/tomoyo/domain.c     1970-01-01 09:00:00.000000000 
+0900
+++ linux-2.6.21.5-tomoyo/security/tomoyo/domain.c      2007-06-05 
00:00:00.000000000 +0900
@@ -0,0 +1,782 @@
+/*
+ * security/tomoyo/domain.c
+ *
+ * Domain transition functions for TOMOYO Linux.
+ *
+ * Copyright (C) 2005-2007  NTT DATA CORPORATION
+ *
+ * Version: 2.0   2007/06/05
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+#include <linux/highmem.h>
+#include <linux/binfmts.h>
+
+#ifndef for_each_process
+#define for_each_process for_each_task
+#endif
+
+/*************************  VARIABLES  *************************/
+
+/* /sbin/init started? */
+extern int sbin_init_started;
+
+/* Lock for appending domain's ACL. */
+DECLARE_MUTEX(domain_acl_lock);
+
+/***** The structure for program files to force domain reconstruction. *****/
+
+struct domain_initializer_entry {
+       struct domain_initializer_entry *next;
+       const struct path_info *domainname;    /* This may be NULL */
+       const struct path_info *program;
+       u8 is_deleted;
+       u8 is_not;
+       u8 is_last_name;
+       u8 is_oldstyle;
+};
+
+/***** The structure for domains to not to transit domains. *****/
+
+struct domain_keeper_entry {
+       struct domain_keeper_entry *next;
+       const struct path_info *domainname;
+       const struct path_info *program;       /* This may be NULL */
+       u8 is_deleted;
+       u8 is_not;
+       u8 is_last_name;
+};
+
+/***** The structure for program files that should be aggregated. *****/
+
+struct aggregator_entry {
+       struct aggregator_entry *next;
+       const struct path_info *original_name;
+       const struct path_info *aggregated_name;
+       int is_deleted;
+};
+
+/***** The structure for program files that should be aliased. *****/
+
+struct alias_entry {
+       struct alias_entry *next;
+       const struct path_info *original_name;
+       const struct path_info *aliased_name;
+       int is_deleted;
+};
+
+/*************************  VARIABLES  *************************/
+
+/* Domain creation lock. */
+static DECLARE_MUTEX(new_domain_assign_lock);
+
+/*************************  UTILITY FUNCTIONS  *************************/
+
+int tomoyo_is_domain_def(const unsigned char *buffer)
+{
+       /* while (*buffer && (*buffer <= ' ' || *buffer >= 127)) buffer++; */
+       return strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN) == 0;
+}
+
+const char *tomoyo_get_last_name(const struct domain_info *domain)
+{
+       const char *cp0 = domain->domainname->name, *cp1;
+       if ((cp1 = strrchr(cp0, ' ')) != NULL) return cp1 + 1;
+       return cp0;
+}
+
+int tomoyo_read_self_domain(struct io_buffer *head)
+{
+       if (!head->read_eof) {
+               tomoyo_io_printf(head,
+                                "%s",
+                                ((struct tomoyo_security *) 
current->security)->domain_info->domainname->name);
+               head->read_eof = 1;
+       }
+       return 0;
+}
+
+int tomoyo_add_domain_acl(struct acl_info *ptr, struct domain_info *domain, 
struct acl_info *new_ptr)
+{
+       mb(); /* Instead of using spinlock. */
+       if (!ptr) domain->first_acl_ptr = (struct acl_info *) new_ptr;
+       else ptr->next = (struct acl_info *) new_ptr;
+       tomoyo_update_counter(TOMOYO_UPDATES_COUNTER_DOMAIN_POLICY);
+       return 0;
+}
+
+int tomoyo_del_domain_acl(struct acl_info *ptr)
+{
+       ptr->is_deleted = 1;
+       tomoyo_update_counter(TOMOYO_UPDATES_COUNTER_DOMAIN_POLICY);
+       return 0;
+}
+
+int tomoyo_too_many_domain_acl(struct domain_info * const domain) {
+       unsigned int count = 0;
+       struct acl_info *ptr;
+       for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
+               if (!ptr->is_deleted) count++;
+       }
+       /* If there are so many entries, don't append if accept mode. */
+       if (count < tomoyo_check_flags(TOMOYO_MAX_ACCEPT_ENTRY)) return 0;
+       if (!domain->quota_warned) {
+               printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. "
+                      "Stopped auto-append mode.\n", domain->domainname->name);
+               domain->quota_warned = 1;
+       }
+       return 1;
+}
+
+
+/*************************  DOMAIN INITIALIZER HANDLER  
*************************/
+
+static struct domain_initializer_entry *domain_initializer_list = NULL;
+
+static int tomoyo_add_domain_initializer_entry(const char *domainname,
+                                               const char *program,
+                                               const int is_not,
+                                               const int is_delete,
+                                               const int is_oldstyle)
+{
+       struct domain_initializer_entry *new_entry, *ptr;
+       static DECLARE_MUTEX(lock);
+       const struct path_info *saved_program, *saved_domainname = NULL;
+       int error = -ENOMEM;
+       int is_last_name = 0;
+       if (!tomoyo_is_correct_path(program, 1, -1, -1, __FUNCTION__))
+               return -EINVAL; /* No patterns allowed. */
+       if (domainname) {
+               if (!tomoyo_is_domain_def(domainname) &&
+                   tomoyo_is_correct_path(domainname, 1, -1, -1, 
__FUNCTION__)) {
+                       is_last_name = 1;
+               } else if (!tomoyo_is_correct_domain(domainname, __FUNCTION__)) 
{
+                       return -EINVAL;
+               }
+               if ((saved_domainname = tomoyo_save_name(domainname)) == NULL) 
return -ENOMEM;
+       }
+       if ((saved_program = tomoyo_save_name(program)) == NULL) return -ENOMEM;
+       down(&lock);
+       for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {
+               if (ptr->is_not == is_not &&
+                   ptr->is_oldstyle == is_oldstyle &&
+                   ptr->domainname == saved_domainname &&
+                   ptr->program == saved_program) {
+                       ptr->is_deleted = is_delete;
+                       error = 0;
+                       goto out;
+               }
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       if ((new_entry = tomoyo_alloc_element(sizeof(*new_entry))) == NULL) 
goto out;
+       new_entry->domainname = saved_domainname;
+       new_entry->program = saved_program;
+       new_entry->is_not = is_not;
+       new_entry->is_last_name = is_last_name;
+       new_entry->is_oldstyle = is_oldstyle;
+       mb(); /* Instead of using spinlock. */
+       if ((ptr = domain_initializer_list) != NULL) {
+               while (ptr->next)
+                       ptr = ptr->next;
+               ptr->next = new_entry;
+       } else {
+               domain_initializer_list = new_entry;
+       }
+       error = 0;
+ out:
+       up(&lock);
+       return error;
+}
+
+int tomoyo_read_domain_initializer_policy(struct io_buffer *head)
+{
+       struct domain_initializer_entry *ptr = head->read_var2;
+       if (!ptr) ptr = domain_initializer_list;
+       while (ptr) {
+               head->read_var2 = ptr;
+               if (!ptr->is_deleted) {
+                       if (ptr->domainname) {
+                               if (tomoyo_io_printf(head,
+                                                    "%s%s%s from %s\n",
+ ptr->is_not ? "no_" : "", + ptr->is_oldstyle ?
+                                                       
TOMOYO_KEYWORD_INITIALIZER : TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+                                                    ptr->program->name, 
ptr->domainname->name))
+                                       break;
+                       } else {
+                               if (tomoyo_io_printf(head,
+                                                    "%s%s%s\n",
+                                                    ptr->is_not ? "no_" : "",
+                                                    ptr->is_oldstyle ?
+                                                       
TOMOYO_KEYWORD_INITIALIZER : TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+                                                    ptr->program->name))
+                                       break;
+                       }
+               }
+               ptr = ptr->next;
+       }
+       return ptr ? -ENOMEM : 0;
+}
+
+int tomoyo_add_domain_initializer_policy(char *data,
+                                         const int is_not,
+                                         const int is_delete,
+                                         const int is_oldstyle)
+{
+       char *cp = strstr(data, " from ");
+       if (cp) {
+               *cp = '\0';
+               return tomoyo_add_domain_initializer_entry(cp + 6,
+                                                          data,
+                                                          is_not,
+                                                          is_delete,
+                                                          is_oldstyle);
+       } else {
+               return tomoyo_add_domain_initializer_entry(NULL,
+                                                          data,
+                                                          is_not,
+                                                          is_delete,
+                                                          is_oldstyle);
+       }
+}
+
+static int tomoyo_is_domain_initializer(const struct path_info *domainname,
+                                        const struct path_info *program,
+                                        const struct path_info *last_name)
+{
+       struct domain_initializer_entry *ptr;
+       int flag = 0;
+       for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {
+               if (ptr->is_deleted ) continue;
+               if (ptr->domainname) {
+                       if (!ptr->is_last_name) {
+                               if (ptr->domainname != domainname) continue;
+                       } else {
+                               if (tomoyo_pathcmp(ptr->domainname, last_name)) 
continue;
+                       }
+               }
+               if (tomoyo_pathcmp(ptr->program, program)) continue;
+               if (ptr->is_not) return 0;
+               flag = 1;
+       }
+       return flag;
+}
+
+/*************************  DOMAIN KEEPER HANDLER  *************************/
+
+static struct domain_keeper_entry *domain_keeper_list = NULL;
+
+static int tomoyo_add_domain_keeper_entry(const char *domainname,
+                                          const char *program,
+                                          const int is_not,
+                                          const int is_delete)
+{
+       struct domain_keeper_entry *new_entry, *ptr;
+       const struct path_info *saved_domainname, *saved_program = NULL;
+       static DECLARE_MUTEX(lock);
+       int error = -ENOMEM;
+       int is_last_name = 0;
+       if (!tomoyo_is_domain_def(domainname) &&
+           tomoyo_is_correct_path(domainname, 1, -1, -1, __FUNCTION__)) {
+               is_last_name = 1;
+       } else if (!tomoyo_is_correct_domain(domainname, __FUNCTION__)) {
+               return -EINVAL;
+       }
+       if (program) {
+               if (!tomoyo_is_correct_path(program, 1, -1, -1, __FUNCTION__)) 
return -EINVAL;
+               if ((saved_program = tomoyo_save_name(program)) == NULL) return 
-ENOMEM;
+       }
+       if ((saved_domainname = tomoyo_save_name(domainname)) == NULL) return 
-ENOMEM;
+       down(&lock);
+       for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {
+               if (ptr->is_not == is_not && ptr->domainname == saved_domainname 
&&
+                   ptr->program == saved_program) {
+                       ptr->is_deleted = is_delete;
+                       error = 0;
+                       goto out;
+               }
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       if ((new_entry = tomoyo_alloc_element(sizeof(*new_entry))) == NULL) 
goto out;
+       new_entry->domainname = saved_domainname;
+       new_entry->program = saved_program;
+       new_entry->is_not = is_not;
+       new_entry->is_last_name = is_last_name;
+       mb(); /* Instead of using spinlock. */
+       if ((ptr = domain_keeper_list) != NULL) {
+               while (ptr->next)
+                       ptr = ptr->next;
+               ptr->next = new_entry;
+       } else {
+               domain_keeper_list = new_entry;
+       }
+       error = 0;
+ out:
+       up(&lock);
+       return error;
+}
+
+int tomoyo_add_domain_keeper_policy(char *data, const int is_not, const int 
is_delete)
+{
+       char *cp = strstr(data, " from ");
+       if (cp) {
+               *cp = '\0';
+               return tomoyo_add_domain_keeper_entry(cp + 6, data, is_not, 
is_delete);
+       } else {
+               return tomoyo_add_domain_keeper_entry(data, NULL, is_not, 
is_delete);
+       }
+}
+
+int tomoyo_read_domain_keeper_policy(struct io_buffer *head)
+{
+       struct domain_keeper_entry *ptr = head->read_var2;
+       if (!ptr) ptr = domain_keeper_list;
+       while (ptr) {
+               head->read_var2 = ptr;
+               if (!ptr->is_deleted) {
+                       if (ptr->program) {
+                               if (tomoyo_io_printf(head,
+                                                    "%s" TOMOYO_KEYWORD_KEEP_DOMAIN 
"%s from %s\n",
+                                                    ptr->is_not ? "no_" : "",
+                                                    ptr->program->name,
+                                                    ptr->domainname->name))
+                                       break;
+                       } else {
+                               if (tomoyo_io_printf(head,
+                                                    "%s" TOMOYO_KEYWORD_KEEP_DOMAIN 
"%s\n",
+                                                    ptr->is_not ? "no_" : "",
+                                                    ptr->domainname->name))
+                                       break;
+                       }
+               }
+               ptr = ptr->next;
+       }
+       return ptr ? -ENOMEM : 0;
+}
+
+static int tomoyo_is_domain_keeper(const struct path_info *domainname,
+                                   const struct path_info *program,
+                                   const struct path_info *last_name)
+{
+       struct domain_keeper_entry *ptr;
+       int flag = 0;
+       for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {
+               if (ptr->is_deleted) continue;
+               if (!ptr->is_last_name) {
+                       if (ptr->domainname != domainname) continue;
+               } else {
+ if (tomoyo_pathcmp(ptr->domainname, last_name)) continue; + }
+               if (ptr->program && tomoyo_pathcmp(ptr->program, program)) 
continue;
+               if (ptr->is_not) return 0;
+               flag = 1;
+       }
+       return flag;
+}
+
+/*************************  SYMBOLIC LINKED PROGRAM HANDLER  
*************************/
+
+static struct alias_entry *alias_list = NULL;
+
+static int tomoyo_add_alias_entry(const char *original_name, const char 
*aliased_name, const int is_delete)
+{
+       struct alias_entry *new_entry, *ptr;
+       static DECLARE_MUTEX(lock);
+       const struct path_info *saved_original_name, *saved_aliased_name;
+       int error = -ENOMEM;
+       if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __FUNCTION__) ||
+           !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __FUNCTION__))
+               return -EINVAL; /* No patterns allowed. */
+       if ((saved_original_name = tomoyo_save_name(original_name)) == NULL ||
+           (saved_aliased_name = tomoyo_save_name(aliased_name)) == NULL)
+               return -ENOMEM;
+       down(&lock);
+       for (ptr = alias_list; ptr; ptr = ptr->next) {
+               if (ptr->original_name == saved_original_name &&
+                   ptr->aliased_name == saved_aliased_name) {
+                       ptr->is_deleted = is_delete;
+                       error = 0;
+                       goto out;
+               }
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       if ((new_entry = tomoyo_alloc_element(sizeof(*new_entry))) == NULL) 
goto out;
+       new_entry->original_name = saved_original_name;
+       new_entry->aliased_name = saved_aliased_name;
+       mb(); /* Instead of using spinlock. */
+       if ((ptr = alias_list) != NULL) {
+               while (ptr->next)
+                       ptr = ptr->next;
+               ptr->next = new_entry;
+       } else {
+               alias_list = new_entry;
+       }
+       error = 0;
+ out:
+       up(&lock);
+       return error;
+}
+
+int tomoyo_read_alias_policy(struct io_buffer *head)
+{
+       struct alias_entry *ptr = head->read_var2;
+       if (!ptr) ptr = alias_list;
+       while (ptr) {
+               head->read_var2 = ptr;
+               if (!ptr->is_deleted &&
+                   tomoyo_io_printf(head,
+                                    TOMOYO_KEYWORD_ALIAS "%s %s\n",
+                                    ptr->original_name->name,
+                                    ptr->aliased_name->name))
+                       break;
+               ptr = ptr->next;
+       }
+       return ptr ? -ENOMEM : 0;
+}
+
+int tomoyo_add_alias_policy(char *data, const int is_delete)
+{
+       char *cp = strchr(data, ' ');
+       if (!cp) return -EINVAL;
+       *cp++ = '\0';
+       return tomoyo_add_alias_entry(data, cp, is_delete);
+}
+
+/*************************  DOMAIN AGGREGATOR HANDLER  
*************************/
+
+static struct aggregator_entry *aggregator_list = NULL;
+
+static int tomoyo_add_aggregator_entry(const char *original_name,
+                                       const char *aggregated_name,
+                                       const int is_delete)
+{
+       struct aggregator_entry *new_entry, *ptr;
+       static DECLARE_MUTEX(lock);
+       const struct path_info *saved_original_name, *saved_aggregated_name;
+       int error = -ENOMEM;
+       if (!tomoyo_is_correct_path(original_name, 1, 0, -1, __FUNCTION__) ||
+           !tomoyo_is_correct_path(aggregated_name, 1, -1, -1, __FUNCTION__))
+               return -EINVAL;
+       if ((saved_original_name = tomoyo_save_name(original_name)) == NULL ||
+           (saved_aggregated_name = tomoyo_save_name(aggregated_name)) == NULL)
+               return -ENOMEM;
+       down(&lock);
+       for (ptr = aggregator_list; ptr; ptr = ptr->next) {
+               if (ptr->original_name == saved_original_name &&
+                   ptr->aggregated_name == saved_aggregated_name) {
+                       ptr->is_deleted = is_delete;
+                       error = 0;
+                       goto out;
+               }
+       }
+       if (is_delete) {
+               error = -ENOENT;
+               goto out;
+       }
+       if ((new_entry = tomoyo_alloc_element(sizeof(*new_entry))) == NULL) 
goto out;
+       new_entry->original_name = saved_original_name;
+       new_entry->aggregated_name = saved_aggregated_name;
+       mb(); /* Instead of using spinlock. */
+       if ((ptr = aggregator_list) != NULL) {
+               while (ptr->next)
+                       ptr = ptr->next;
+               ptr->next = new_entry;
+       } else {
+               aggregator_list = new_entry;
+       }
+       error = 0;
+ out:
+       up(&lock);
+       return error;
+}
+
+int tomoyo_read_aggregator_policy(struct io_buffer *head)
+{
+       struct aggregator_entry *ptr = head->read_var2;
+       if (!ptr) ptr = aggregator_list;
+       while (ptr) {
+               head->read_var2 = ptr;
+               if (!ptr->is_deleted &&
+                   tomoyo_io_printf(head,
+                                    TOMOYO_KEYWORD_AGGREGATOR "%s %s\n",
+                                    ptr->original_name->name,
+                                    ptr->aggregated_name->name))
+                       break;
+               ptr = ptr->next;
+       }
+       return ptr ? -ENOMEM : 0;
+}
+
+int tomoyo_add_aggregator_policy(char *data, const int is_delete)
+{
+       char *cp = strchr(data, ' ');
+       if (!cp) return -EINVAL;
+       *cp++ = '\0';
+       return tomoyo_add_aggregator_entry(data, cp, is_delete);
+}
+
+/*************************  DOMAIN DELETION HANDLER  *************************/
+
+int tomoyo_delete_domain(char *domainname0)
+{
+       struct domain_info *domain;
+       struct path_info domainname;
+       domainname.name = domainname0;
+       tomoyo_fill_path_info(&domainname);
+       down(&new_domain_assign_lock);
+       /* Is there an active domain? */ /* Never delete KERNEL_DOMAIN */
+       for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
+               if (domain->is_deleted || tomoyo_pathcmp(domain->domainname, 
&domainname)) continue;
+               break;
+       }
+       if (domain) {
+               struct domain_info *domain2;
+               /* Mark already deleted domains as non undeletable. */
+               for (domain2 = KERNEL_DOMAIN.next; domain2; domain2 = 
domain2->next) {
+                       if (!domain2->is_deleted || 
tomoyo_pathcmp(domain2->domainname, &domainname))
+                               continue;
+                       domain2->is_deleted = 255;
+               }
+               /* Delete and mark active domain as undeletable. */
+               domain->is_deleted = 1;
+       }
+       up(&new_domain_assign_lock);
+       return 0;
+}
+
+struct domain_info *tomoyo_undelete_domain(const char *domainname0)
+{
+       struct domain_info *domain, *candidate_domain = NULL;
+       struct path_info domainname;
+       domainname.name = domainname0;
+       tomoyo_fill_path_info(&domainname);
+       down(&new_domain_assign_lock);
+       for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
+               if (tomoyo_pathcmp(&domainname, domain->domainname)) continue;
+               if (!domain->is_deleted) {
+                       /* This domain is active. I can't undelete. */
+                       candidate_domain = NULL;
+                       break;
+               }
+               /* Is this domain undeletable? */
+               if (domain->is_deleted == 1) candidate_domain = domain;
+       }
+       if (candidate_domain) {
+               candidate_domain->is_deleted = 0;
+       }
+       up(&new_domain_assign_lock);
+       return candidate_domain;
+}
+
+/*************************  DOMAIN TRANSITION HANDLER  
*************************/
+
+struct domain_info *tomoyo_find_domain(const char *domainname0)
+{
+       struct domain_info *domain;
+       static int first = 1;
+       struct path_info domainname;
+       domainname.name = domainname0;
+       tomoyo_fill_path_info(&domainname);
+       if (first) {
+               KERNEL_DOMAIN.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
+               first = 0;
+       }
+       for (domain = &KERNEL_DOMAIN; domain; domain = domain->next) {
+               if (!domain->is_deleted && !tomoyo_pathcmp(&domainname, 
domain->domainname))
+                       return domain;
+       }
+       return NULL;
+}
+
+struct domain_info *tomoyo_find_or_assign_new_domain(const char *domainname, 
const u8 profile)
+{
+       struct domain_info *domain = NULL;
+       const struct path_info *saved_domainname;
+       down(&new_domain_assign_lock);
+       if ((domain = tomoyo_find_domain(domainname)) != NULL) goto out;
+       if (!tomoyo_is_correct_domain(domainname, __FUNCTION__)) goto out;
+       if ((saved_domainname = tomoyo_save_name(domainname)) == NULL) goto out;
+       /* Can I reuse memory of deleted domain? */
+       for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {
+               struct task_struct *p;
+               struct acl_info *ptr;
+               int flag;
+               if (!domain->is_deleted || domain->domainname != 
saved_domainname) continue;
+               flag = 0;
+               /***** CRITICAL SECTION START *****/
+               read_lock(&tasklist_lock);
+               for_each_process(p) {
+                       if (p->security == domain) {
+                               flag = 1;
+                               break;
+                       }
+               }
+               read_unlock(&tasklist_lock);
+               /***** CRITICAL SECTION END *****/
+               if (flag) continue;
+               for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) 
ptr->is_deleted = 1;
+               domain->profile = profile;
+               domain->quota_warned = 0;
+               mb(); /* Instead of using spinlock. */
+               domain->is_deleted = 0;
+               goto out;
+       }
+       /* No memory reusable. Create using new memory. */
+       if ((domain = tomoyo_alloc_element(sizeof(*domain))) != NULL) {
+               struct domain_info *ptr = &KERNEL_DOMAIN;
+               domain->domainname = saved_domainname;
+               domain->profile = profile;
+               mb(); /* Instead of using spinlock. */
+               while (ptr->next)
+                       ptr = ptr->next;
+               ptr->next = domain;
+       }
+ out: ;
+       up(&new_domain_assign_lock);
+       return domain;
+}
+
+int tomoyo_find_next_domain(struct linux_binprm *bprm, struct domain_info 
**next_domain)
+{
+       /* This function assumes that the size of buffer returned */
+       /* by tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. */
+       struct domain_info *old_domain =
+               ((struct tomoyo_security *) current->security)->domain_info, 
*domain = NULL;
+       const char *old_domain_name = old_domain->domainname->name;
+       const char *original_name = bprm->filename;
+       struct file *filp = bprm->file;
+       char *new_domain_name = NULL;
+       char *real_program_name = NULL, *symlink_program_name = NULL;
+       const int is_enforce = tomoyo_check_enforce(TOMOYO_MAC_FOR_FILE);
+       int retval;
+       struct path_info r, s, l;
+
+       {
+               /*
+                * Built-in initializers.
+                * This is needed because policies are not loaded until 
starting /sbin/init .
+                */
+               static int first = 1;
+               if (first) {
+                       tomoyo_add_domain_initializer_entry(NULL, 
"/sbin/hotplug", 0, 0, 0);
+                       tomoyo_add_domain_initializer_entry(NULL, 
"/sbin/modprobe", 0, 0, 0);
+                       first = 0;
+               }
+       }
+
+       /* Get realpath of program. */
+       retval = -ENOENT; /* I hope tomoyo_realpath() won't fail with -ENOMEM. 
*/
+       if ((real_program_name = tomoyo_realpath(original_name)) == NULL) goto 
out;
+       /* Get realpath of symbolic link. */
+       if ((symlink_program_name = tomoyo_realpath_nofollow(original_name)) == 
NULL) goto out;
+
+       r.name = real_program_name;
+       tomoyo_fill_path_info(&r);
+       s.name = symlink_program_name;
+       tomoyo_fill_path_info(&s);
+       if ((l.name = strrchr(old_domain_name, ' ')) != NULL) l.name++;
+       else l.name = old_domain_name;
+       tomoyo_fill_path_info(&l);
+
+       /* Check 'alias' directive. */
+       if (tomoyo_pathcmp(&r, &s)) {
+               struct alias_entry *ptr;
+               /* Is this program allowed to be called via symbolic links? */
+               for (ptr = alias_list; ptr; ptr = ptr->next) {
+                       if (ptr->is_deleted ||
+                           tomoyo_pathcmp(&r, ptr->original_name) ||
+                           tomoyo_pathcmp(&s, ptr->aliased_name))
+                               continue;
+                       memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
+                       strncpy(real_program_name,
+                               ptr->aliased_name->name,
+                               TOMOYO_MAX_PATHNAME_LEN - 1);
+                       tomoyo_fill_path_info(&r);
+                       break;
+               }
+       }
+       
+       /* Check 'aggregator' directive. */
+       {
+               struct aggregator_entry *ptr;
+               /* Is this program allowed to be aggregated? */
+               for (ptr = aggregator_list; ptr; ptr = ptr->next) {
+                       if (ptr->is_deleted ||
+                           !tomoyo_path_matches_to_pattern(&r, 
ptr->original_name))
+                               continue;
+                       memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
+                       strncpy(real_program_name,
+                               ptr->aggregated_name->name,
+                               TOMOYO_MAX_PATHNAME_LEN - 1);
+                       tomoyo_fill_path_info(&r);
+                       break;
+               }
+       }
+       
+       /* Check execute permission. */
+       if ((retval = tomoyo_check_exec_perm(&r, filp)) < 0) goto out;
+
+       /* Allocate memory for calcurating domain name. */
+       retval = -ENOMEM;
+       if ((new_domain_name = tomoyo_alloc(TOMOYO_MAX_PATHNAME_LEN + 16)) == 
NULL) goto out;
+       
+       if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
+               /* Transit to the child of KERNEL_DOMAIN domain. */
+               snprintf(new_domain_name,
+                        TOMOYO_MAX_PATHNAME_LEN + 1,
+                        TOMOYO_ROOT_NAME " " "%s",
+                        real_program_name);
+       } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {
+               /*
+                * Needn't to transit from kernel domain before starting 
/sbin/init .
+                * But transit from kernel domain if executing initializers,
+                * for they might start before /sbin/init .
+                */
+               domain = old_domain;
+       } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
+               /* Keep current domain. */
+               domain = old_domain;
+       } else {
+               /* Normal domain transition. */
+               snprintf(new_domain_name,
+                        TOMOYO_MAX_PATHNAME_LEN + 1,
+                        "%s %s",
+                        old_domain_name,
+                        real_program_name);
+       }
+       if (!domain && strlen(new_domain_name) < TOMOYO_MAX_PATHNAME_LEN) {
+               if (is_enforce) {
+                       domain = tomoyo_find_domain(new_domain_name);
+                       if (!domain)
+                               if (tomoyo_check_supervisor("#Need to create 
domain\n%s\n",
+                                   new_domain_name) == 0)
+                                       domain = 
tomoyo_find_or_assign_new_domain(new_domain_name,
+                                                                                 
((struct tomoyo_security *) current->security)->domain_info->profile);
+               } else {
+                       domain = 
tomoyo_find_or_assign_new_domain(new_domain_name,
+                                                                 ((struct 
tomoyo_security *) current->security)->domain_info->profile);
+               }
+       }
+       if (!domain) {
+               printk("TOMOYO-ERROR: Domain '%s' not defined.\n", 
new_domain_name);
+               if (is_enforce) retval = -EPERM;
+       } else {
+               retval = 0;
+       }
+ out: ;
+       tomoyo_free(new_domain_name);
+       tomoyo_free(real_program_name);
+       tomoyo_free(symlink_program_name);
+       *next_domain = domain ? domain : old_domain;
+       return retval;
+}
---------------

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to