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/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]