Messages in this thread Patch in this message | | | Date | Thu, 14 Jun 2007 16:39:29 +0900 | From | Kentaro Takeda <> | Subject | [TOMOYO 9/9] Domain transition handler functions. |
| |
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 <takedakn@nttdata.co.jp> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
--------------- 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 majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |