]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - security/tomoyo/domain.c
TOMOYO: Use GFP_NOFS rather than GFP_KERNEL.
[net-next-2.6.git] / security / tomoyo / domain.c
index 229de1e71a38cc4f0bfd5ae0bb37b0ad18f2ae9e..ed5141883242e577b3734e607576b5396f124964 100644 (file)
@@ -10,8 +10,6 @@
  */
 
 #include "common.h"
-#include "tomoyo.h"
-#include "realpath.h"
 #include <linux/binfmts.h>
 
 /* Variables definitions.*/
@@ -59,76 +57,6 @@ struct tomoyo_domain_info tomoyo_kernel_domain;
  */
 LIST_HEAD(tomoyo_domain_list);
 
-/*
- * tomoyo_domain_initializer_entry is a structure which is used for holding
- * "initialize_domain" and "no_initialize_domain" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_domain_initializer_list .
- *  (2) "domainname" which is "a domainname" or "the last component of a
- *      domainname". This field is NULL if "from" clause is not specified.
- *  (3) "program" which is a program's pathname.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
- *      otherwise.
- *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
- *      component of a domainname", false otherwise.
- */
-struct tomoyo_domain_initializer_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *domainname;    /* This may be NULL */
-       const struct tomoyo_path_info *program;
-       bool is_deleted;
-       bool is_not;       /* True if this entry is "no_initialize_domain".  */
-       /* True if the domainname is tomoyo_get_last_name(). */
-       bool is_last_name;
-};
-
-/*
- * tomoyo_domain_keeper_entry is a structure which is used for holding
- * "keep_domain" and "no_keep_domain" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_domain_keeper_list .
- *  (2) "domainname" which is "a domainname" or "the last component of a
- *      domainname".
- *  (3) "program" which is a program's pathname.
- *      This field is NULL if "from" clause is not specified.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
- *      otherwise.
- *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
- *      component of a domainname", false otherwise.
- */
-struct tomoyo_domain_keeper_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *domainname;
-       const struct tomoyo_path_info *program;       /* This may be NULL */
-       bool is_deleted;
-       bool is_not;       /* True if this entry is "no_keep_domain".        */
-       /* True if the domainname is tomoyo_get_last_name(). */
-       bool is_last_name;
-};
-
-/*
- * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_alias_list .
- *  (2) "original_name" which is a dereferenced pathname.
- *  (3) "aliased_name" which is a symlink's pathname.
- *  (4) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
- */
-struct tomoyo_alias_entry {
-       struct list_head list;
-       const struct tomoyo_path_info *original_name;
-       const struct tomoyo_path_info *aliased_name;
-       bool is_deleted;
-};
-
 /**
  * tomoyo_get_last_name - Get last component of a domainname.
  *
@@ -182,7 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
  * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
  * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
  */
-static LIST_HEAD(tomoyo_domain_initializer_list);
+LIST_HEAD(tomoyo_domain_initializer_list);
 
 /**
  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
@@ -203,28 +131,28 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
 {
        struct tomoyo_domain_initializer_entry *entry = NULL;
        struct tomoyo_domain_initializer_entry *ptr;
-       const struct tomoyo_path_info *saved_program;
+       const struct tomoyo_path_info *saved_program = NULL;
        const struct tomoyo_path_info *saved_domainname = NULL;
        int error = is_delete ? -ENOENT : -ENOMEM;
        bool is_last_name = false;
 
-       if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
+       if (!tomoyo_is_correct_path(program, 1, -1, -1))
                return -EINVAL; /* No patterns allowed. */
        if (domainname) {
                if (!tomoyo_is_domain_def(domainname) &&
-                   tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
+                   tomoyo_is_correct_path(domainname, 1, -1, -1))
                        is_last_name = true;
-               else if (!tomoyo_is_correct_domain(domainname, __func__))
+               else if (!tomoyo_is_correct_domain(domainname))
                        return -EINVAL;
-               saved_domainname = tomoyo_save_name(domainname);
+               saved_domainname = tomoyo_get_name(domainname);
                if (!saved_domainname)
                        goto out;
        }
-       saved_program = tomoyo_save_name(program);
+       saved_program = tomoyo_get_name(program);
        if (!saved_program)
                goto out;
        if (!is_delete)
-               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+               entry = kmalloc(sizeof(*entry), GFP_NOFS);
        mutex_lock(&tomoyo_policy_lock);
        list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
                if (ptr->is_not != is_not ||
@@ -237,7 +165,9 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->domainname = saved_domainname;
+               saved_domainname = NULL;
                entry->program = saved_program;
+               saved_program = NULL;
                entry->is_not = is_not;
                entry->is_last_name = is_last_name;
                list_add_tail_rcu(&entry->list,
@@ -247,6 +177,8 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_domainname);
+       tomoyo_put_name(saved_program);
        kfree(entry);
        return error;
 }
@@ -398,7 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
  * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
  * explicitly specified by "initialize_domain".
  */
-static LIST_HEAD(tomoyo_domain_keeper_list);
+LIST_HEAD(tomoyo_domain_keeper_list);
 
 /**
  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
@@ -419,28 +351,28 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
 {
        struct tomoyo_domain_keeper_entry *entry = NULL;
        struct tomoyo_domain_keeper_entry *ptr;
-       const struct tomoyo_path_info *saved_domainname;
+       const struct tomoyo_path_info *saved_domainname = NULL;
        const struct tomoyo_path_info *saved_program = NULL;
        int error = is_delete ? -ENOENT : -ENOMEM;
        bool is_last_name = false;
 
        if (!tomoyo_is_domain_def(domainname) &&
-           tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
+           tomoyo_is_correct_path(domainname, 1, -1, -1))
                is_last_name = true;
-       else if (!tomoyo_is_correct_domain(domainname, __func__))
+       else if (!tomoyo_is_correct_domain(domainname))
                return -EINVAL;
        if (program) {
-               if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
+               if (!tomoyo_is_correct_path(program, 1, -1, -1))
                        return -EINVAL;
-               saved_program = tomoyo_save_name(program);
+               saved_program = tomoyo_get_name(program);
                if (!saved_program)
                        goto out;
        }
-       saved_domainname = tomoyo_save_name(domainname);
+       saved_domainname = tomoyo_get_name(domainname);
        if (!saved_domainname)
                goto out;
        if (!is_delete)
-               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+               entry = kmalloc(sizeof(*entry), GFP_NOFS);
        mutex_lock(&tomoyo_policy_lock);
        list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
                if (ptr->is_not != is_not ||
@@ -453,7 +385,9 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->domainname = saved_domainname;
+               saved_domainname = NULL;
                entry->program = saved_program;
+               saved_program = NULL;
                entry->is_not = is_not;
                entry->is_last_name = is_last_name;
                list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list);
@@ -462,6 +396,8 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_domainname);
+       tomoyo_put_name(saved_program);
        kfree(entry);
        return error;
 }
@@ -597,7 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
  * /bin/busybox and domainname which the current process will belong to after
  * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
  */
-static LIST_HEAD(tomoyo_alias_list);
+LIST_HEAD(tomoyo_alias_list);
 
 /**
  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
@@ -620,15 +556,15 @@ static int tomoyo_update_alias_entry(const char *original_name,
        const struct tomoyo_path_info *saved_aliased_name;
        int error = is_delete ? -ENOENT : -ENOMEM;
 
-       if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
-           !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
+       if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
+           !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
                return -EINVAL; /* No patterns allowed. */
-       saved_original_name = tomoyo_save_name(original_name);
-       saved_aliased_name = tomoyo_save_name(aliased_name);
+       saved_original_name = tomoyo_get_name(original_name);
+       saved_aliased_name = tomoyo_get_name(aliased_name);
        if (!saved_original_name || !saved_aliased_name)
                goto out;
        if (!is_delete)
-               entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+               entry = kmalloc(sizeof(*entry), GFP_NOFS);
        mutex_lock(&tomoyo_policy_lock);
        list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
                if (ptr->original_name != saved_original_name ||
@@ -640,13 +576,17 @@ static int tomoyo_update_alias_entry(const char *original_name,
        }
        if (!is_delete && error && tomoyo_memory_ok(entry)) {
                entry->original_name = saved_original_name;
+               saved_original_name = NULL;
                entry->aliased_name = saved_aliased_name;
+               saved_aliased_name = NULL;
                list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
                entry = NULL;
                error = 0;
        }
        mutex_unlock(&tomoyo_policy_lock);
  out:
+       tomoyo_put_name(saved_original_name);
+       tomoyo_put_name(saved_aliased_name);
        kfree(entry);
        return error;
 }
@@ -719,12 +659,12 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
        const struct tomoyo_path_info *saved_domainname;
        bool found = false;
 
-       if (!tomoyo_is_correct_domain(domainname, __func__))
+       if (!tomoyo_is_correct_domain(domainname))
                return NULL;
-       saved_domainname = tomoyo_save_name(domainname);
+       saved_domainname = tomoyo_get_name(domainname);
        if (!saved_domainname)
                return NULL;
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       entry = kzalloc(sizeof(*entry), GFP_NOFS);
        mutex_lock(&tomoyo_policy_lock);
        list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
                if (domain->is_deleted ||
@@ -736,6 +676,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
        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;
@@ -743,6 +684,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
                found = true;
        }
        mutex_unlock(&tomoyo_policy_lock);
+       tomoyo_put_name(saved_domainname);
        kfree(entry);
        return found ? domain : NULL;
 }
@@ -762,7 +704,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
         * This function assumes that the size of buffer returned by
         * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
         */
-       struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+       struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
        struct tomoyo_domain_info *old_domain = tomoyo_domain();
        struct tomoyo_domain_info *domain = NULL;
        const char *old_domain_name = old_domain->domainname->name;
@@ -875,6 +817,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
  out:
        if (!domain)
                domain = old_domain;
+       /* Update reference count on "struct tomoyo_domain_info". */
+       atomic_inc(&domain->users);
        bprm->cred->security = domain;
        kfree(real_program_name);
        kfree(symlink_program_name);