lkml.org 
[lkml]   [2009]   [May]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[TOMOYO] Add garbage collector support.
    From
    Date
    A process who is reading/writing list elements has pointers which point to
    (possibly marked-as-deleted) list elements and releases a lock when the process
    leaves the kernel.

    As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
    because TOMOYO does not manage list of pointers.

    This patch makes TOMOYO to manage list of pointers and allows an administrator
    release memory used by marked-as-deleted list elements.

    Memory Management Rules:

    When reading list elements, a process takes tomoyo_policy_lock for reading.
    When writing list elements, a process takes tomoyo_policy_lock for writing.

    When a process finished reading list elements, a garbage collector function
    is called after the process released tomoyo_policy_lock.
    The garbage collector function takes tomoyo_policy_lock for writing and
    traverses the lists and releases elements if that element has is_deleted flag
    set.

    Since strings are likely referenced by multiple list elements, this patch
    assigns a refcounter to each string.
    The policy add/del function increments the refcounter only if the element is
    added to the list. The garbage collector function decrements the refcounter
    only if the element is not referred by a process.
    The garbage collector function releases memory of the string if the string's
    refcounter becomes 0.

    "struct tomoyo_io_buffer" remembers pointer to list elements.
    Thus, TOMOYO memorizes the address of "struct tomoyo_io_buffer"->read_var1,
    "struct tomoyo_io_buffer"->read_var2, "struct tomoyo_io_buffer"->write_var1
    when a file in /sys/kernel/security/tomoyo/ interface is opened and forgets
    them when that file is closed.

    "struct task_struct"->cred->security also remembers pointer to list elements.
    Thus, TOMOYO memorizes the address of cred->security at
    security_cred_prepare() and forgets it at security_cred_free().

    tomoyo_update_cookie() is called with tomoyo_policy_lock held for reading
    when the pointer refers a different list element.

    tomoyo_used_by_cookie() is called with tomoyo_policy_lock held for writing
    to check whether the pointer is referenced by a cookie or not.


    Now, TOMOYO can release memory. :-)

    Attached patch is for security-testing-2.6#next.
    James, it is possible to apply below commits to security-testing-2.6#next ?
    I get a lot of warning messages in my environment.

    39826a1e17c1957bd7b5cd7815b83940e5e3a230 tomoyo: version bump to 2.2.0.
    17a7b7b39056a82c5012539311850f202e6c3cd4 tomoyo: add Documentation/tomoyo.txt
    05fa199d45c54a9bda7aa3ae6537253d6f097aa9 mm: pass correct mm when growing stack
    05f54c13cd0c33694eec39a265475c5d6cf223cf Revert "kobject: don't block for each kobject_uevent".
    a964e33c5d7c0ea46376d20c2f02edf01c9db251 x86: clean up old gcc warnings


    Regards.
    --------------------
    Subject: [TOMOYO] Add garbage collector support.

    A process who is reading/writing list elements has pointers which point to
    (possibly marked-as-deleted) list elements and releases a lock when the process
    leaves the kernel.

    As of now, TOMOYO cannot release memory used by marked-as-deleted list elements
    because TOMOYO does not manage list of pointers.

    This patch makes TOMOYO to manage list of pointers and allows an administrator
    release memory used by marked-as-deleted list elements.

    Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
    Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
    ---
    security/tomoyo/common.c | 259 ++++++++++++++++++++++++++++----------------
    security/tomoyo/common.h | 37 ++++--
    security/tomoyo/domain.c | 237 ++++++++++++++++++++++++----------------
    security/tomoyo/file.c | 188 +++++++++++++++++++++++---------
    security/tomoyo/realpath.c | 264 ++++++++++++++++++++++++++-------------------
    security/tomoyo/realpath.h | 43 +++++--
    security/tomoyo/tomoyo.c | 40 ++++--
    security/tomoyo/tomoyo.h | 13 --
    8 files changed, 689 insertions(+), 392 deletions(-)

    --- security-testing-2.6.git.orig/security/tomoyo/common.c
    +++ security-testing-2.6.git/security/tomoyo/common.c
    @@ -12,8 +12,8 @@
    #include <linux/uaccess.h>
    #include <linux/security.h>
    #include <linux/hardirq.h>
    -#include "realpath.h"
    #include "common.h"
    +#include "realpath.h"
    #include "tomoyo.h"

    /* Has loading policy done? */
    @@ -326,13 +326,13 @@ bool tomoyo_is_domain_def(const unsigned
    * tomoyo_find_domain - Find a domain by the given name.
    *
    * @domainname: The domainname to find.
    + * @cookie: Pointer to "struct tomoyo_cookie".
    *
    - * Caller must call down_read(&tomoyo_domain_list_lock); or
    - * down_write(&tomoyo_domain_list_lock); .
    + * Caller must hold tomoyo_policy_lock.
    *
    - * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
    + * Returns true if found, false otherwise.
    */
    -struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
    +bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie)
    {
    struct tomoyo_domain_info *domain;
    struct tomoyo_path_info name;
    @@ -340,11 +340,13 @@ struct tomoyo_domain_info *tomoyo_find_d
    name.name = domainname;
    tomoyo_fill_path_info(&name);
    list_for_each_entry(domain, &tomoyo_domain_list, list) {
    - if (!domain->is_deleted &&
    - !tomoyo_pathcmp(&name, domain->domainname))
    - return domain;
    + if (domain->is_deleted ||
    + tomoyo_pathcmp(&name, domain->domainname))
    + continue;
    + tomoyo_update_cookie(cookie, domain);
    + return true;
    }
    - return NULL;
    + return false;
    }

    /**
    @@ -784,7 +786,7 @@ bool tomoyo_domain_quota_is_ok(struct to

    if (!domain)
    return true;
    - down_read(&tomoyo_domain_acl_info_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &domain->acl_info_list, list) {
    if (ptr->type & TOMOYO_ACL_DELETED)
    continue;
    @@ -838,7 +840,7 @@ bool tomoyo_domain_quota_is_ok(struct to
    break;
    }
    }
    - up_read(&tomoyo_domain_acl_info_list_lock);
    + up_read(&tomoyo_policy_lock);
    if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
    return true;
    if (!domain->quota_warned) {
    @@ -915,7 +917,10 @@ static int tomoyo_write_profile(struct t
    return -EINVAL;
    *cp = '\0';
    if (!strcmp(data, "COMMENT")) {
    + down_write(&tomoyo_policy_lock);
    + tomoyo_del_name(profile->comment);
    profile->comment = tomoyo_save_name(cp + 1);
    + up_write(&tomoyo_policy_lock);
    return 0;
    }
    for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
    @@ -973,9 +978,13 @@ static int tomoyo_read_profile(struct to
    if (!profile)
    continue;
    if (!type) { /* Print profile' comment tag. */
    - if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
    - index, profile->comment ?
    - profile->comment->name : ""))
    + bool done;
    + down_read(&tomoyo_policy_lock);
    + done = tomoyo_io_printf(head, "%u-COMMENT=%s\n",
    + index, profile->comment ?
    + profile->comment->name : "");
    + up_read(&tomoyo_policy_lock);
    + if (!done)
    break;
    continue;
    }
    @@ -1020,7 +1029,6 @@ struct tomoyo_policy_manager_entry {

    /* The list for "struct tomoyo_policy_manager_entry". */
    static LIST_HEAD(tomoyo_policy_manager_list);
    -static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);

    /**
    * tomoyo_update_manager_entry - Add a manager entry.
    @@ -1051,7 +1059,7 @@ static int tomoyo_update_manager_entry(c
    if (!saved_manager)
    return -ENOMEM;
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_policy_manager_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
    if (ptr->manager != saved_manager)
    continue;
    @@ -1067,11 +1075,13 @@ static int tomoyo_update_manager_entry(c
    if (!new_entry)
    goto out;
    new_entry->manager = saved_manager;
    + saved_manager = NULL;
    new_entry->is_domain = is_domain;
    list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
    error = 0;
    out:
    - up_write(&tomoyo_policy_manager_list_lock);
    + tomoyo_del_name(saved_manager);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -1095,6 +1105,23 @@ static int tomoyo_write_manager_policy(s
    return tomoyo_update_manager_entry(data, is_delete);
    }

    +static void tomoyo_cleanup_manager(void)
    +{
    + struct tomoyo_policy_manager_entry *ptr;
    + struct tomoyo_policy_manager_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_policy_manager_list, list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->manager);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_manager_policy - Read manager policy.
    *
    @@ -1109,8 +1136,8 @@ static int tomoyo_read_manager_policy(st

    if (head->read_eof)
    return 0;
    - down_read(&tomoyo_policy_manager_list_lock);
    - list_for_each_cookie(pos, head->read_var2,
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list,
    &tomoyo_policy_manager_list) {
    struct tomoyo_policy_manager_entry *ptr;
    ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
    @@ -1122,8 +1149,10 @@ static int tomoyo_read_manager_policy(st
    break;
    }
    }
    - up_read(&tomoyo_policy_manager_list_lock);
    + up_read(&tomoyo_policy_lock);
    head->read_eof = done;
    + if (done)
    + tomoyo_cleanup_manager();
    return 0;
    }

    @@ -1145,7 +1174,7 @@ static bool tomoyo_is_policy_manager(voi
    return true;
    if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
    return false;
    - down_read(&tomoyo_policy_manager_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
    if (!ptr->is_deleted && ptr->is_domain
    && !tomoyo_pathcmp(domainname, ptr->manager)) {
    @@ -1153,13 +1182,13 @@ static bool tomoyo_is_policy_manager(voi
    break;
    }
    }
    - up_read(&tomoyo_policy_manager_list_lock);
    + up_read(&tomoyo_policy_lock);
    if (found)
    return true;
    exe = tomoyo_get_exe();
    if (!exe)
    return false;
    - down_read(&tomoyo_policy_manager_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
    if (!ptr->is_deleted && !ptr->is_domain
    && !strcmp(exe, ptr->manager->name)) {
    @@ -1167,7 +1196,7 @@ static bool tomoyo_is_policy_manager(voi
    break;
    }
    }
    - up_read(&tomoyo_policy_manager_list_lock);
    + up_read(&tomoyo_policy_lock);
    if (!found) { /* Reduce error messages. */
    static pid_t last_pid;
    const pid_t pid = current->pid;
    @@ -1194,25 +1223,30 @@ static bool tomoyo_is_select_one(struct
    {
    unsigned int pid;
    struct tomoyo_domain_info *domain = NULL;
    + struct tomoyo_cookie *cookie = &head->write_var1;

    if (sscanf(data, "pid=%u", &pid) == 1) {
    struct task_struct *p;
    + down_read(&tomoyo_policy_lock);
    /***** CRITICAL SECTION START *****/
    - read_lock(&tasklist_lock);
    + rcu_read_lock();
    p = find_task_by_vpid(pid);
    if (p)
    domain = tomoyo_real_domain(p);
    - read_unlock(&tasklist_lock);
    + rcu_read_unlock();
    /***** CRITICAL SECTION END *****/
    + if (domain)
    + tomoyo_update_cookie(cookie, domain);
    + up_read(&tomoyo_policy_lock);
    } else if (!strncmp(data, "domain=", 7)) {
    if (tomoyo_is_domain_def(data + 7)) {
    - down_read(&tomoyo_domain_list_lock);
    - domain = tomoyo_find_domain(data + 7);
    - up_read(&tomoyo_domain_list_lock);
    + down_read(&tomoyo_policy_lock);
    + if (tomoyo_find_domain(data + 7, cookie))
    + domain = cookie->u.domain;
    + up_read(&tomoyo_policy_lock);
    }
    } else
    return false;
    - head->write_var1 = domain;
    /* Accessing read_buf is safe because head->io_sem is held. */
    if (!head->read_buf)
    return true; /* Do nothing if open(O_WRONLY). */
    @@ -1222,15 +1256,15 @@ static bool tomoyo_is_select_one(struct
    head->read_eof = !domain;
    if (domain) {
    struct tomoyo_domain_info *d;
    - head->read_var1 = NULL;
    - down_read(&tomoyo_domain_list_lock);
    + head->read_var1.u.domain = NULL;
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(d, &tomoyo_domain_list, list) {
    if (d == domain)
    break;
    - head->read_var1 = &d->list;
    + head->read_var1.u.list = &d->list;
    }
    - up_read(&tomoyo_domain_list_lock);
    - head->read_var2 = NULL;
    + up_read(&tomoyo_policy_lock);
    + head->read_var2.u.list = NULL;
    head->read_bit = 0;
    head->read_step = 0;
    if (domain->is_deleted)
    @@ -1249,7 +1283,7 @@ static bool tomoyo_is_select_one(struct
    static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
    {
    char *data = head->write_buf;
    - struct tomoyo_domain_info *domain = head->write_var1;
    + struct tomoyo_domain_info *domain = head->write_var1.u.domain;
    bool is_delete = false;
    bool is_select = false;
    unsigned int profile;
    @@ -1264,16 +1298,16 @@ static int tomoyo_write_domain_policy(st
    if (!tomoyo_is_policy_manager())
    return -EPERM;
    if (tomoyo_is_domain_def(data)) {
    - domain = NULL;
    - if (is_delete)
    + struct tomoyo_cookie *cookie = &head->write_var1;
    + if (is_delete) {
    tomoyo_delete_domain(data);
    - else if (is_select) {
    - down_read(&tomoyo_domain_list_lock);
    - domain = tomoyo_find_domain(data);
    - up_read(&tomoyo_domain_list_lock);
    + tomoyo_update_cookie(cookie, NULL);
    + } else if (is_select) {
    + down_read(&tomoyo_policy_lock);
    + tomoyo_find_domain(data, cookie);
    + up_read(&tomoyo_policy_lock);
    } else
    - domain = tomoyo_find_or_assign_new_domain(data, 0);
    - head->write_var1 = domain;
    + tomoyo_find_or_assign_new_domain(data, 0, cookie);
    return 0;
    }
    if (!domain)
    @@ -1410,6 +1444,57 @@ static bool tomoyo_print_entry(struct to
    return false;
    }

    +static void tomoyo_cleanup_domain_policy(void)
    +{
    + struct tomoyo_domain_info *domain;
    + struct tomoyo_domain_info *next_domain;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(domain, next_domain, &tomoyo_domain_list,
    + list) {
    + struct tomoyo_acl_info *acl;
    + struct tomoyo_acl_info *next_acl;
    + const bool can_delete_domain = domain->is_deleted &&
    + !tomoyo_used_by_cookie(domain);
    + if (can_delete_domain) {
    + list_for_each_entry(acl, &domain->acl_info_list, list)
    + acl->type |= TOMOYO_ACL_DELETED;
    + }
    + list_for_each_entry_safe(acl, next_acl, &domain->acl_info_list,
    + list) {
    + if (!(acl->type & TOMOYO_ACL_DELETED)
    + || tomoyo_used_by_cookie(acl))
    + continue;
    + list_del(&acl->list);
    + switch (tomoyo_acl_type1(acl)) {
    + struct tomoyo_single_path_acl_record *acl1;
    + struct tomoyo_double_path_acl_record *acl2;
    + case TOMOYO_TYPE_SINGLE_PATH_ACL:
    + acl1 = container_of(acl,
    + struct tomoyo_single_path_acl_record,
    + head);
    + tomoyo_del_name(acl1->filename);
    + break;
    + case TOMOYO_TYPE_DOUBLE_PATH_ACL:
    + acl2 = container_of(acl,
    + struct tomoyo_double_path_acl_record,
    + head);
    + tomoyo_del_name(acl2->filename1);
    + tomoyo_del_name(acl2->filename2);
    + break;
    + }
    + tomoyo_free_element(acl);
    + }
    + if (can_delete_domain && list_empty(&domain->acl_info_list)) {
    + tomoyo_del_name(domain->domainname);
    + list_del(&domain->list);
    + tomoyo_free_element(domain);
    + }
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_domain_policy - Read domain policy.
    *
    @@ -1427,8 +1512,9 @@ static int tomoyo_read_domain_policy(str
    return 0;
    if (head->read_step == 0)
    head->read_step = 1;
    - down_read(&tomoyo_domain_list_lock);
    - list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(dpos, head->read_var1.u.list,
    + &tomoyo_domain_list) {
    struct tomoyo_domain_info *domain;
    const char *quota_exceeded = "";
    const char *transition_failed = "";
    @@ -1461,18 +1547,16 @@ acl_loop:
    if (head->read_step == 3)
    goto tail_mark;
    /* Print ACL entries in the domain. */
    - down_read(&tomoyo_domain_acl_info_list_lock);
    - list_for_each_cookie(apos, head->read_var2,
    - &domain->acl_info_list) {
    + list_for_each_cookie(apos, head->read_var2.u.list,
    + &domain->acl_info_list) {
    struct tomoyo_acl_info *ptr
    = list_entry(apos, struct tomoyo_acl_info,
    - list);
    + list);
    if (!tomoyo_print_entry(head, ptr)) {
    done = false;
    break;
    }
    }
    - up_read(&tomoyo_domain_acl_info_list_lock);
    if (!done)
    break;
    head->read_step = 3;
    @@ -1485,8 +1569,10 @@ tail_mark:
    if (head->read_single_domain)
    break;
    }
    - up_read(&tomoyo_domain_list_lock);
    + up_read(&tomoyo_policy_lock);
    head->read_eof = done;
    + if (done)
    + tomoyo_cleanup_domain_policy();
    return 0;
    }

    @@ -1496,30 +1582,25 @@ tail_mark:
    * @head: Pointer to "struct tomoyo_io_buffer".
    *
    * Returns 0 on success, -EINVAL otherwise.
    - *
    - * This is equivalent to doing
    - *
    - * ( echo "select " $domainname; echo "use_profile " $profile ) |
    - * /usr/lib/ccs/loadpolicy -d
    */
    static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
    {
    char *data = head->write_buf;
    char *cp = strchr(data, ' ');
    - struct tomoyo_domain_info *domain;
    unsigned long profile;
    + struct tomoyo_cookie cookie;

    if (!cp)
    return -EINVAL;
    *cp = '\0';
    - down_read(&tomoyo_domain_list_lock);
    - domain = tomoyo_find_domain(cp + 1);
    - up_read(&tomoyo_domain_list_lock);
    - if (strict_strtoul(data, 10, &profile))
    + if (strict_strtoul(data, 10, &profile) ||
    + profile >= TOMOYO_MAX_PROFILES)
    return -EINVAL;
    - if (domain && profile < TOMOYO_MAX_PROFILES
    - && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
    - domain->profile = (u8) profile;
    + down_read(&tomoyo_policy_lock);
    + if (tomoyo_find_domain(cp + 1, &cookie) &&
    + (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
    + cookie.u.domain->profile = (u8) profile;
    + up_read(&tomoyo_policy_lock);
    return 0;
    }

    @@ -1529,13 +1610,6 @@ static int tomoyo_write_domain_profile(s
    * @head: Pointer to "struct tomoyo_io_buffer".
    *
    * Returns list of profile number and domainname pairs.
    - *
    - * This is equivalent to doing
    - *
    - * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
    - * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
    - * domainname = $0; } else if ( $1 == "use_profile" ) {
    - * print $2 " " domainname; domainname = ""; } } ; '
    */
    static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
    {
    @@ -1544,8 +1618,8 @@ static int tomoyo_read_domain_profile(st

    if (head->read_eof)
    return 0;
    - down_read(&tomoyo_domain_list_lock);
    - list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var1.u.list, &tomoyo_domain_list) {
    struct tomoyo_domain_info *domain;
    domain = list_entry(pos, struct tomoyo_domain_info, list);
    if (domain->is_deleted)
    @@ -1556,7 +1630,7 @@ static int tomoyo_read_domain_profile(st
    break;
    }
    }
    - up_read(&tomoyo_domain_list_lock);
    + up_read(&tomoyo_policy_lock);
    head->read_eof = done;
    return 0;
    }
    @@ -1595,11 +1669,11 @@ static int tomoyo_read_pid(struct tomoyo
    struct task_struct *p;
    struct tomoyo_domain_info *domain = NULL;
    /***** CRITICAL SECTION START *****/
    - read_lock(&tasklist_lock);
    + rcu_read_lock();
    p = find_task_by_vpid(pid);
    if (p)
    domain = tomoyo_real_domain(p);
    - read_unlock(&tasklist_lock);
    + rcu_read_unlock();
    /***** CRITICAL SECTION END *****/
    if (domain)
    tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
    @@ -1655,43 +1729,43 @@ static int tomoyo_read_exception_policy(
    if (!head->read_eof) {
    switch (head->read_step) {
    case 0:
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 1;
    case 1:
    if (!tomoyo_read_domain_keeper_policy(head))
    break;
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 2;
    case 2:
    if (!tomoyo_read_globally_readable_policy(head))
    break;
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 3;
    case 3:
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 4;
    case 4:
    if (!tomoyo_read_domain_initializer_policy(head))
    break;
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 5;
    case 5:
    if (!tomoyo_read_alias_policy(head))
    break;
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 6;
    case 6:
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 7;
    case 7:
    if (!tomoyo_read_file_pattern(head))
    break;
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 8;
    case 8:
    if (!tomoyo_read_no_rewrite_policy(head))
    break;
    - head->read_var2 = NULL;
    + head->read_var2.u.list = NULL;
    head->read_step = 9;
    case 9:
    head->read_eof = true;
    @@ -1778,7 +1852,7 @@ void tomoyo_load_policy(const char *file
    tomoyo_policy_loaded = true;
    { /* Check all profiles currently assigned to domains are defined. */
    struct tomoyo_domain_info *domain;
    - down_read(&tomoyo_domain_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(domain, &tomoyo_domain_list, list) {
    const u8 profile = domain->profile;
    if (tomoyo_profile_ptr[profile])
    @@ -1786,7 +1860,7 @@ void tomoyo_load_policy(const char *file
    panic("Profile %u (used by '%s') not defined.\n",
    profile, domain->domainname->name);
    }
    - up_read(&tomoyo_domain_list_lock);
    + up_read(&tomoyo_policy_lock);
    }
    }

    @@ -1919,6 +1993,9 @@ static int tomoyo_open_control(const u8
    return -ENOMEM;
    }
    }
    + tomoyo_add_cookie(&head->read_var1, NULL);
    + tomoyo_add_cookie(&head->read_var2, NULL);
    + tomoyo_add_cookie(&head->write_var1, NULL);
    file->private_data = head;
    /*
    * Call the handler now if the file is
    @@ -2043,6 +2120,9 @@ static int tomoyo_close_control(struct f
    head->read_buf = NULL;
    tomoyo_free(head->write_buf);
    head->write_buf = NULL;
    + tomoyo_del_cookie(&head->read_var1);
    + tomoyo_del_cookie(&head->read_var2);
    + tomoyo_del_cookie(&head->write_var1);
    tomoyo_free(head);
    head = NULL;
    file->private_data = NULL;
    @@ -2171,9 +2251,10 @@ static void __init tomoyo_create_entry(c
    static int __init tomoyo_initerface_init(void)
    {
    struct dentry *tomoyo_dir;
    + struct tomoyo_cookie *cookie = current_cred()->security;

    /* Don't create securityfs entries unless registered. */
    - if (current_cred()->security != &tomoyo_kernel_domain)
    + if (!cookie || cookie->u.domain != &tomoyo_kernel_domain)
    return 0;

    tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
    --- security-testing-2.6.git.orig/security/tomoyo/common.h
    +++ security-testing-2.6.git/security/tomoyo/common.h
    @@ -26,6 +26,18 @@
    struct dentry;
    struct vfsmount;

    +struct tomoyo_domain_info;
    +struct tomoyo_path_info;
    +struct tomoyo_cookie {
    + struct list_head list;
    + union {
    + const void *ptr;
    + struct list_head *list;
    + struct tomoyo_domain_info *domain;
    + const struct tomoyo_path_info *path;
    + } u;
    +};
    +
    /* Temporary buffer for holding pathnames. */
    struct tomoyo_page_buffer {
    char buffer[4096];
    @@ -160,11 +172,11 @@ struct tomoyo_io_buffer {
    /* Exclusive lock for this structure. */
    struct mutex io_sem;
    /* The position currently reading from. */
    - struct list_head *read_var1;
    + struct tomoyo_cookie read_var1;
    /* Extra variables for reading. */
    - struct list_head *read_var2;
    + struct tomoyo_cookie read_var2;
    /* The position currently writing to. */
    - struct tomoyo_domain_info *write_var1;
    + struct tomoyo_cookie write_var1;
    /* The step for reading. */
    int read_step;
    /* Buffer for reading. */
    @@ -258,11 +270,10 @@ int tomoyo_write_no_rewrite_policy(char
    /* Create "file_pattern" entry in exception policy. */
    int tomoyo_write_pattern_policy(char *data, const bool is_delete);
    /* Find a domain by the given name. */
    -struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
    +bool tomoyo_find_domain(const char *domainname, struct tomoyo_cookie *cookie);
    /* Find or create a domain by the given name. */
    -struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
    - domainname,
    - const u8 profile);
    +bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
    + struct tomoyo_cookie *cookie);
    /* Check mode for specified functionality. */
    unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
    const u8 index);
    @@ -276,6 +287,11 @@ void tomoyo_load_policy(const char *file
    void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
    const bool is_delete, const u8 flags);

    +static inline struct tomoyo_domain_info *tomoyo_domain(void)
    +{
    + return ((struct tomoyo_cookie *) current_cred()->security)->u.domain;
    +}
    +
    /* strcmp() for "struct tomoyo_path_info" structure. */
    static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
    const struct tomoyo_path_info *b)
    @@ -319,12 +335,11 @@ static inline bool tomoyo_is_invalid(con
    return c && (c <= ' ' || c >= 127);
    }

    +/* Lock for modifying policy. */
    +extern struct rw_semaphore tomoyo_policy_lock;
    +
    /* The list for "struct tomoyo_domain_info". */
    extern struct list_head tomoyo_domain_list;
    -extern struct rw_semaphore tomoyo_domain_list_lock;
    -
    -/* Lock for domain->acl_info_list. */
    -extern struct rw_semaphore tomoyo_domain_acl_info_list_lock;

    /* Has /sbin/init started? */
    extern bool tomoyo_policy_loaded;
    --- security-testing-2.6.git.orig/security/tomoyo/domain.c
    +++ security-testing-2.6.git/security/tomoyo/domain.c
    @@ -21,7 +21,7 @@ struct tomoyo_domain_info tomoyo_kernel_

    /* The list for "struct tomoyo_domain_info". */
    LIST_HEAD(tomoyo_domain_list);
    -DECLARE_RWSEM(tomoyo_domain_list_lock);
    +DECLARE_RWSEM(tomoyo_policy_lock);

    /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
    struct tomoyo_domain_initializer_entry {
    @@ -96,7 +96,6 @@ const char *tomoyo_get_last_name(const s

    /* The list for "struct tomoyo_domain_initializer_entry". */
    static LIST_HEAD(tomoyo_domain_initializer_list);
    -static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);

    /**
    * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
    @@ -133,10 +132,12 @@ static int tomoyo_update_domain_initiali
    return -ENOMEM;
    }
    saved_program = tomoyo_save_name(program);
    - if (!saved_program)
    + if (!saved_program) {
    + tomoyo_del_name(saved_domainname);
    return -ENOMEM;
    + }
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_domain_initializer_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
    if (ptr->is_not != is_not ||
    ptr->domainname != saved_domainname ||
    @@ -154,17 +155,40 @@ static int tomoyo_update_domain_initiali
    if (!new_entry)
    goto out;
    new_entry->domainname = saved_domainname;
    + saved_domainname = NULL;
    new_entry->program = saved_program;
    + saved_program = NULL;
    new_entry->is_not = is_not;
    new_entry->is_last_name = is_last_name;
    list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
    error = 0;
    out:
    - up_write(&tomoyo_domain_initializer_list_lock);
    + tomoyo_del_name(saved_domainname);
    + tomoyo_del_name(saved_program);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }

    +static void tomoyo_cleanup_initializer(void)
    +{
    + struct tomoyo_domain_initializer_entry *ptr;
    + struct tomoyo_domain_initializer_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_initializer_list,
    + list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->domainname);
    + tomoyo_del_name(ptr->program);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
    *
    @@ -177,8 +201,8 @@ bool tomoyo_read_domain_initializer_poli
    struct list_head *pos;
    bool done = true;

    - down_read(&tomoyo_domain_initializer_list_lock);
    - list_for_each_cookie(pos, head->read_var2,
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list,
    &tomoyo_domain_initializer_list) {
    const char *no;
    const char *from = "";
    @@ -201,7 +225,9 @@ bool tomoyo_read_domain_initializer_poli
    break;
    }
    }
    - up_read(&tomoyo_domain_initializer_list_lock);
    + up_read(&tomoyo_policy_lock);
    + if (done)
    + tomoyo_cleanup_initializer();
    return done;
    }

    @@ -248,7 +274,7 @@ static bool tomoyo_is_domain_initializer
    struct tomoyo_domain_initializer_entry *ptr;
    bool flag = false;

    - down_read(&tomoyo_domain_initializer_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
    if (ptr->is_deleted)
    continue;
    @@ -269,13 +295,12 @@ static bool tomoyo_is_domain_initializer
    }
    flag = true;
    }
    - up_read(&tomoyo_domain_initializer_list_lock);
    + up_read(&tomoyo_policy_lock);
    return flag;
    }

    /* The list for "struct tomoyo_domain_keeper_entry". */
    static LIST_HEAD(tomoyo_domain_keeper_list);
    -static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);

    /**
    * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
    @@ -313,10 +338,12 @@ static int tomoyo_update_domain_keeper_e
    return -ENOMEM;
    }
    saved_domainname = tomoyo_save_name(domainname);
    - if (!saved_domainname)
    + if (!saved_domainname) {
    + tomoyo_del_name(saved_program);
    return -ENOMEM;
    + }
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_domain_keeper_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
    if (ptr->is_not != is_not ||
    ptr->domainname != saved_domainname ||
    @@ -334,13 +361,17 @@ static int tomoyo_update_domain_keeper_e
    if (!new_entry)
    goto out;
    new_entry->domainname = saved_domainname;
    + saved_domainname = NULL;
    new_entry->program = saved_program;
    + saved_program = NULL;
    new_entry->is_not = is_not;
    new_entry->is_last_name = is_last_name;
    list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
    error = 0;
    out:
    - up_write(&tomoyo_domain_keeper_list_lock);
    + tomoyo_del_name(saved_domainname);
    + tomoyo_del_name(saved_program);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -366,6 +397,24 @@ int tomoyo_write_domain_keeper_policy(ch
    return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
    }

    +static void tomoyo_cleanup_keep_domain(void)
    +{
    + struct tomoyo_domain_keeper_entry *ptr;
    + struct tomoyo_domain_keeper_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_keeper_list, list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->domainname);
    + tomoyo_del_name(ptr->program);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
    *
    @@ -378,8 +427,8 @@ bool tomoyo_read_domain_keeper_policy(st
    struct list_head *pos;
    bool done = true;

    - down_read(&tomoyo_domain_keeper_list_lock);
    - list_for_each_cookie(pos, head->read_var2,
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list,
    &tomoyo_domain_keeper_list) {
    struct tomoyo_domain_keeper_entry *ptr;
    const char *no;
    @@ -402,7 +451,9 @@ bool tomoyo_read_domain_keeper_policy(st
    break;
    }
    }
    - up_read(&tomoyo_domain_keeper_list_lock);
    + up_read(&tomoyo_policy_lock);
    + if (done)
    + tomoyo_cleanup_keep_domain();
    return done;
    }

    @@ -423,7 +474,7 @@ static bool tomoyo_is_domain_keeper(cons
    struct tomoyo_domain_keeper_entry *ptr;
    bool flag = false;

    - down_read(&tomoyo_domain_keeper_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
    if (ptr->is_deleted)
    continue;
    @@ -442,13 +493,12 @@ static bool tomoyo_is_domain_keeper(cons
    }
    flag = true;
    }
    - up_read(&tomoyo_domain_keeper_list_lock);
    + up_read(&tomoyo_policy_lock);
    return flag;
    }

    /* The list for "struct tomoyo_alias_entry". */
    static LIST_HEAD(tomoyo_alias_list);
    -static DECLARE_RWSEM(tomoyo_alias_list_lock);

    /**
    * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
    @@ -474,10 +524,13 @@ static int tomoyo_update_alias_entry(con
    return -EINVAL; /* No patterns allowed. */
    saved_original_name = tomoyo_save_name(original_name);
    saved_aliased_name = tomoyo_save_name(aliased_name);
    - if (!saved_original_name || !saved_aliased_name)
    + if (!saved_original_name || !saved_aliased_name) {
    + tomoyo_del_name(saved_original_name);
    + tomoyo_del_name(saved_aliased_name);
    return -ENOMEM;
    + }
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_alias_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_alias_list, list) {
    if (ptr->original_name != saved_original_name ||
    ptr->aliased_name != saved_aliased_name)
    @@ -494,15 +547,37 @@ static int tomoyo_update_alias_entry(con
    if (!new_entry)
    goto out;
    new_entry->original_name = saved_original_name;
    + saved_original_name = NULL;
    new_entry->aliased_name = saved_aliased_name;
    + saved_aliased_name = NULL;
    list_add_tail(&new_entry->list, &tomoyo_alias_list);
    error = 0;
    out:
    - up_write(&tomoyo_alias_list_lock);
    + tomoyo_del_name(saved_original_name);
    + tomoyo_del_name(saved_aliased_name);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }

    +static void tomoyo_cleanup_alias(void)
    +{
    + struct tomoyo_alias_entry *ptr;
    + struct tomoyo_alias_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_alias_list, list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->original_name);
    + tomoyo_del_name(ptr->aliased_name);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
    *
    @@ -515,8 +590,8 @@ bool tomoyo_read_alias_policy(struct tom
    struct list_head *pos;
    bool done = true;

    - down_read(&tomoyo_alias_list_lock);
    - list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list, &tomoyo_alias_list) {
    struct tomoyo_alias_entry *ptr;

    ptr = list_entry(pos, struct tomoyo_alias_entry, list);
    @@ -529,7 +604,9 @@ bool tomoyo_read_alias_policy(struct tom
    break;
    }
    }
    - up_read(&tomoyo_alias_list_lock);
    + up_read(&tomoyo_policy_lock);
    + if (done)
    + tomoyo_cleanup_alias();
    return done;
    }

    @@ -568,7 +645,7 @@ int tomoyo_delete_domain(char *domainnam
    name.name = domainname;
    tomoyo_fill_path_info(&name);
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_domain_list_lock);
    + down_write(&tomoyo_policy_lock);
    /* Is there an active domain? */
    list_for_each_entry(domain, &tomoyo_domain_list, list) {
    /* Never delete tomoyo_kernel_domain */
    @@ -580,7 +657,7 @@ int tomoyo_delete_domain(char *domainnam
    domain->is_deleted = true;
    break;
    }
    - up_write(&tomoyo_domain_list_lock);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return 0;
    }
    @@ -590,81 +667,49 @@ int tomoyo_delete_domain(char *domainnam
    *
    * @domainname: The name of domain.
    * @profile: Profile number to assign if the domain was newly created.
    + * @cookie: Pointer to "struct tomoyo_cookie".
    *
    - * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
    + * Returns true on success, false otherwise.
    */
    -struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
    - domainname,
    - const u8 profile)
    +bool tomoyo_find_or_assign_new_domain(const char *domainname, const u8 profile,
    + struct tomoyo_cookie *cookie)
    {
    - struct tomoyo_domain_info *domain = NULL;
    - const struct tomoyo_path_info *saved_domainname;
    + struct tomoyo_domain_info *domain;
    + const struct tomoyo_path_info *saved_domainname = NULL;

    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_domain_list_lock);
    - domain = tomoyo_find_domain(domainname);
    - if (domain)
    + down_write(&tomoyo_policy_lock);
    + if (tomoyo_find_domain(domainname, cookie))
    goto out;
    if (!tomoyo_is_correct_domain(domainname, __func__))
    goto out;
    saved_domainname = tomoyo_save_name(domainname);
    if (!saved_domainname)
    goto out;
    - /* Can I reuse memory of deleted domain? */
    - list_for_each_entry(domain, &tomoyo_domain_list, list) {
    - struct task_struct *p;
    - struct tomoyo_acl_info *ptr;
    - bool flag;
    - if (!domain->is_deleted ||
    - domain->domainname != saved_domainname)
    - continue;
    - flag = false;
    - /***** CRITICAL SECTION START *****/
    - read_lock(&tasklist_lock);
    - for_each_process(p) {
    - if (tomoyo_real_domain(p) != domain)
    - continue;
    - flag = true;
    - break;
    - }
    - read_unlock(&tasklist_lock);
    - /***** CRITICAL SECTION END *****/
    - if (flag)
    - continue;
    - list_for_each_entry(ptr, &domain->acl_info_list, list) {
    - ptr->type |= TOMOYO_ACL_DELETED;
    - }
    - tomoyo_set_domain_flag(domain, true, domain->flags);
    - domain->profile = profile;
    - domain->quota_warned = false;
    - mb(); /* Avoid out-of-order execution. */
    - domain->is_deleted = false;
    - goto out;
    - }
    - /* No memory reusable. Create using new memory. */
    domain = tomoyo_alloc_element(sizeof(*domain));
    if (domain) {
    INIT_LIST_HEAD(&domain->acl_info_list);
    domain->domainname = saved_domainname;
    + saved_domainname = NULL;
    domain->profile = profile;
    list_add_tail(&domain->list, &tomoyo_domain_list);
    + tomoyo_update_cookie(cookie, domain);
    }
    out:
    - up_write(&tomoyo_domain_list_lock);
    + tomoyo_del_name(saved_domainname);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    - return domain;
    + return cookie->u.domain != NULL;
    }

    /**
    * tomoyo_find_next_domain - Find a domain.
    *
    - * @bprm: Pointer to "struct linux_binprm".
    - * @next_domain: Pointer to pointer to "struct tomoyo_domain_info".
    + * @bprm: Pointer to "struct linux_binprm".
    *
    * Returns 0 on success, negative value otherwise.
    */
    -int tomoyo_find_next_domain(struct linux_binprm *bprm,
    - struct tomoyo_domain_info **next_domain)
    +int tomoyo_find_next_domain(struct linux_binprm *bprm)
    {
    /*
    * This function assumes that the size of buffer returned by
    @@ -672,7 +717,6 @@ int tomoyo_find_next_domain(struct linux
    */
    struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
    struct tomoyo_domain_info *old_domain = tomoyo_domain();
    - struct tomoyo_domain_info *domain = NULL;
    const char *old_domain_name = old_domain->domainname->name;
    const char *original_name = bprm->filename;
    char *new_domain_name = NULL;
    @@ -685,6 +729,8 @@ int tomoyo_find_next_domain(struct linux
    struct tomoyo_path_info s; /* symlink name */
    struct tomoyo_path_info l; /* last name */
    static bool initialized;
    + struct tomoyo_cookie *cookie = bprm->cred->security;
    + bool found = false;

    if (!tmp)
    goto out;
    @@ -723,7 +769,7 @@ int tomoyo_find_next_domain(struct linux
    if (tomoyo_pathcmp(&r, &s)) {
    struct tomoyo_alias_entry *ptr;
    /* Is this program allowed to be called via symbolic links? */
    - down_read(&tomoyo_alias_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_alias_list, list) {
    if (ptr->is_deleted ||
    tomoyo_pathcmp(&r, ptr->original_name) ||
    @@ -735,7 +781,7 @@ int tomoyo_find_next_domain(struct linux
    tomoyo_fill_path_info(&r);
    break;
    }
    - up_read(&tomoyo_alias_list_lock);
    + up_read(&tomoyo_policy_lock);
    }

    /* Check execute permission. */
    @@ -755,28 +801,36 @@ int tomoyo_find_next_domain(struct linux
    * /sbin/init. But transit from kernel domain if executing
    * initializers because they might start before /sbin/init.
    */
    - domain = old_domain;
    + found = true;
    + /*
    + * Since old_domain is already in cookie list,
    + * tomoyo_policy_lock is not needed.
    + */
    + tomoyo_update_cookie(cookie, old_domain);
    } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
    /* Keep current domain. */
    - domain = old_domain;
    + found = true;
    + /*
    + * Since old_domain is already in cookie,
    + * tomoyo_policy_lock is not needed.
    + */
    + tomoyo_update_cookie(cookie, 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)
    - goto done;
    - down_read(&tomoyo_domain_list_lock);
    - domain = tomoyo_find_domain(new_domain_name);
    - up_read(&tomoyo_domain_list_lock);
    - if (domain)
    - goto done;
    - if (is_enforce)
    + if (found || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
    goto done;
    - domain = tomoyo_find_or_assign_new_domain(new_domain_name,
    - old_domain->profile);
    + down_read(&tomoyo_policy_lock);
    + found = tomoyo_find_domain(new_domain_name, cookie);
    + up_read(&tomoyo_policy_lock);
    + if (!found && !is_enforce)
    + found = tomoyo_find_or_assign_new_domain(new_domain_name,
    + old_domain->profile,
    + cookie);
    done:
    - if (domain)
    + if (found)
    goto out;
    printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
    new_domain_name);
    @@ -788,7 +842,6 @@ int tomoyo_find_next_domain(struct linux
    out:
    tomoyo_free(real_program_name);
    tomoyo_free(symlink_program_name);
    - *next_domain = domain ? domain : old_domain;
    tomoyo_free(tmp);
    return retval;
    }
    --- security-testing-2.6.git.orig/security/tomoyo/file.c
    +++ security-testing-2.6.git/security/tomoyo/file.c
    @@ -130,9 +130,6 @@ static struct tomoyo_path_info *tomoyo_g
    return NULL;
    }

    -/* Lock for domain->acl_info_list. */
    -DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
    -
    static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
    const char *filename2,
    struct tomoyo_domain_info *
    @@ -143,7 +140,6 @@ static int tomoyo_update_single_path_acl

    /* The list for "struct tomoyo_globally_readable_file_entry". */
    static LIST_HEAD(tomoyo_globally_readable_list);
    -static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);

    /**
    * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
    @@ -167,7 +163,7 @@ static int tomoyo_update_globally_readab
    if (!saved_filename)
    return -ENOMEM;
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_globally_readable_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
    if (ptr->filename != saved_filename)
    continue;
    @@ -183,10 +179,12 @@ static int tomoyo_update_globally_readab
    if (!new_entry)
    goto out;
    new_entry->filename = saved_filename;
    + saved_filename = NULL;
    list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
    error = 0;
    out:
    - up_write(&tomoyo_globally_readable_list_lock);
    + tomoyo_del_name(saved_filename);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -203,7 +201,7 @@ static bool tomoyo_is_globally_readable_
    {
    struct tomoyo_globally_readable_file_entry *ptr;
    bool found = false;
    - down_read(&tomoyo_globally_readable_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
    if (!ptr->is_deleted &&
    tomoyo_path_matches_pattern(filename, ptr->filename)) {
    @@ -211,7 +209,7 @@ static bool tomoyo_is_globally_readable_
    break;
    }
    }
    - up_read(&tomoyo_globally_readable_list_lock);
    + up_read(&tomoyo_policy_lock);
    return found;
    }

    @@ -228,6 +226,24 @@ int tomoyo_write_globally_readable_polic
    return tomoyo_update_globally_readable_entry(data, is_delete);
    }

    +static void tomoyo_cleanup_allow_read(void)
    +{
    + struct tomoyo_globally_readable_file_entry *ptr;
    + struct tomoyo_globally_readable_file_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_globally_readable_list,
    + list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->filename);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
    *
    @@ -240,8 +256,8 @@ bool tomoyo_read_globally_readable_polic
    struct list_head *pos;
    bool done = true;

    - down_read(&tomoyo_globally_readable_list_lock);
    - list_for_each_cookie(pos, head->read_var2,
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list,
    &tomoyo_globally_readable_list) {
    struct tomoyo_globally_readable_file_entry *ptr;
    ptr = list_entry(pos,
    @@ -255,13 +271,14 @@ bool tomoyo_read_globally_readable_polic
    break;
    }
    }
    - up_read(&tomoyo_globally_readable_list_lock);
    + up_read(&tomoyo_policy_lock);
    + if (done)
    + tomoyo_cleanup_allow_read();
    return done;
    }

    /* The list for "struct tomoyo_pattern_entry". */
    static LIST_HEAD(tomoyo_pattern_list);
    -static DECLARE_RWSEM(tomoyo_pattern_list_lock);

    /**
    * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
    @@ -285,7 +302,7 @@ static int tomoyo_update_file_pattern_en
    if (!saved_pattern)
    return -ENOMEM;
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_pattern_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
    if (saved_pattern != ptr->pattern)
    continue;
    @@ -301,10 +318,12 @@ static int tomoyo_update_file_pattern_en
    if (!new_entry)
    goto out;
    new_entry->pattern = saved_pattern;
    + saved_pattern = NULL;
    list_add_tail(&new_entry->list, &tomoyo_pattern_list);
    error = 0;
    out:
    - up_write(&tomoyo_pattern_list_lock);
    + tomoyo_del_name(saved_pattern);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -312,17 +331,15 @@ static int tomoyo_update_file_pattern_en
    /**
    * tomoyo_get_file_pattern - Get patterned pathname.
    *
    - * @filename: The filename to find patterned pathname.
    - *
    - * Returns pointer to pathname pattern if matched, @filename otherwise.
    + * @cookie: Pointer to "struct tomoyo_cookie".
    */
    -static const struct tomoyo_path_info *
    -tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
    +static void tomoyo_get_file_pattern(struct tomoyo_cookie *cookie)
    {
    struct tomoyo_pattern_entry *ptr;
    const struct tomoyo_path_info *pattern = NULL;
    + const struct tomoyo_path_info *filename = cookie->u.path;

    - down_read(&tomoyo_pattern_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
    if (ptr->is_deleted)
    continue;
    @@ -336,10 +353,9 @@ tomoyo_get_file_pattern(const struct tom
    break;
    }
    }
    - up_read(&tomoyo_pattern_list_lock);
    if (pattern)
    - filename = pattern;
    - return filename;
    + tomoyo_update_cookie(cookie, pattern);
    + up_read(&tomoyo_policy_lock);
    }

    /**
    @@ -355,6 +371,23 @@ int tomoyo_write_pattern_policy(char *da
    return tomoyo_update_file_pattern_entry(data, is_delete);
    }

    +static void tomoyo_cleanup_file_pattern(void)
    +{
    + struct tomoyo_pattern_entry *ptr;
    + struct tomoyo_pattern_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_pattern_list, list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->pattern);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
    *
    @@ -367,8 +400,9 @@ bool tomoyo_read_file_pattern(struct tom
    struct list_head *pos;
    bool done = true;

    - down_read(&tomoyo_pattern_list_lock);
    - list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list,
    + &tomoyo_pattern_list) {
    struct tomoyo_pattern_entry *ptr;
    ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
    if (ptr->is_deleted)
    @@ -379,13 +413,14 @@ bool tomoyo_read_file_pattern(struct tom
    break;
    }
    }
    - up_read(&tomoyo_pattern_list_lock);
    + up_read(&tomoyo_policy_lock);
    + if (done)
    + tomoyo_cleanup_file_pattern();
    return done;
    }

    /* The list for "struct tomoyo_no_rewrite_entry". */
    static LIST_HEAD(tomoyo_no_rewrite_list);
    -static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);

    /**
    * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
    @@ -408,7 +443,7 @@ static int tomoyo_update_no_rewrite_entr
    if (!saved_pattern)
    return -ENOMEM;
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_no_rewrite_list_lock);
    + down_write(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
    if (ptr->pattern != saved_pattern)
    continue;
    @@ -424,10 +459,12 @@ static int tomoyo_update_no_rewrite_entr
    if (!new_entry)
    goto out;
    new_entry->pattern = saved_pattern;
    + saved_pattern = NULL;
    list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
    error = 0;
    out:
    - up_write(&tomoyo_no_rewrite_list_lock);
    + tomoyo_del_name(saved_pattern);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -445,7 +482,7 @@ static bool tomoyo_is_no_rewrite_file(co
    struct tomoyo_no_rewrite_entry *ptr;
    bool found = false;

    - down_read(&tomoyo_no_rewrite_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
    if (ptr->is_deleted)
    continue;
    @@ -454,7 +491,7 @@ static bool tomoyo_is_no_rewrite_file(co
    found = true;
    break;
    }
    - up_read(&tomoyo_no_rewrite_list_lock);
    + up_read(&tomoyo_policy_lock);
    return found;
    }

    @@ -471,6 +508,23 @@ int tomoyo_write_no_rewrite_policy(char
    return tomoyo_update_no_rewrite_entry(data, is_delete);
    }

    +static void tomoyo_cleanup_no_rewrite(void)
    +{
    + struct tomoyo_no_rewrite_entry *ptr;
    + struct tomoyo_no_rewrite_entry *tmp;
    + /***** EXCLUSIVE SECTION START *****/
    + down_write(&tomoyo_policy_lock);
    + list_for_each_entry_safe(ptr, tmp, &tomoyo_no_rewrite_list, list) {
    + if (!ptr->is_deleted || tomoyo_used_by_cookie(ptr))
    + continue;
    + list_del(&ptr->list);
    + tomoyo_del_name(ptr->pattern);
    + tomoyo_free_element(ptr);
    + }
    + up_write(&tomoyo_policy_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    /**
    * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
    *
    @@ -483,8 +537,9 @@ bool tomoyo_read_no_rewrite_policy(struc
    struct list_head *pos;
    bool done = true;

    - down_read(&tomoyo_no_rewrite_list_lock);
    - list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
    + down_read(&tomoyo_policy_lock);
    + list_for_each_cookie(pos, head->read_var2.u.list,
    + &tomoyo_no_rewrite_list) {
    struct tomoyo_no_rewrite_entry *ptr;
    ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
    if (ptr->is_deleted)
    @@ -495,7 +550,9 @@ bool tomoyo_read_no_rewrite_policy(struc
    break;
    }
    }
    - up_read(&tomoyo_no_rewrite_list_lock);
    + up_read(&tomoyo_policy_lock);
    + if (done)
    + tomoyo_cleanup_no_rewrite();
    return done;
    }

    @@ -561,7 +618,7 @@ static int tomoyo_check_single_path_acl2
    struct tomoyo_acl_info *ptr;
    int error = -EPERM;

    - down_read(&tomoyo_domain_acl_info_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &domain->acl_info_list, list) {
    struct tomoyo_single_path_acl_record *acl;
    if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
    @@ -580,7 +637,7 @@ static int tomoyo_check_single_path_acl2
    error = 0;
    break;
    }
    - up_read(&tomoyo_domain_acl_info_list_lock);
    + up_read(&tomoyo_policy_lock);
    return error;
    }

    @@ -662,10 +719,17 @@ static int tomoyo_check_file_perm2(struc
    return error;
    if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
    /* Don't use patterns for execute permission. */
    - const struct tomoyo_path_info *patterned_file = (perm != 1) ?
    - tomoyo_get_file_pattern(filename) : filename;
    - tomoyo_update_file_acl(patterned_file->name, perm,
    - domain, false);
    + if (perm == 1) {
    + tomoyo_update_file_acl(filename->name, perm, domain,
    + false);
    + } else {
    + struct tomoyo_cookie cookie;
    + tomoyo_add_cookie(&cookie, filename);
    + tomoyo_get_file_pattern(&cookie);
    + tomoyo_update_file_acl(cookie.u.path->name, perm,
    + domain, false);
    + tomoyo_del_cookie(&cookie);
    + }
    }
    return 0;
    }
    @@ -746,7 +810,7 @@ static int tomoyo_update_single_path_acl
    if (!saved_filename)
    return -ENOMEM;
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_domain_acl_info_list_lock);
    + down_write(&tomoyo_policy_lock);
    if (is_delete)
    goto delete;
    list_for_each_entry(ptr, &domain->acl_info_list, list) {
    @@ -776,6 +840,7 @@ static int tomoyo_update_single_path_acl
    if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
    acl->perm |= rw_mask;
    acl->filename = saved_filename;
    + saved_filename = NULL;
    list_add_tail(&acl->head.list, &domain->acl_info_list);
    error = 0;
    goto out;
    @@ -799,7 +864,8 @@ static int tomoyo_update_single_path_acl
    break;
    }
    out:
    - up_write(&tomoyo_domain_acl_info_list_lock);
    + tomoyo_del_name(saved_filename);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -834,10 +900,13 @@ static int tomoyo_update_double_path_acl
    return -EINVAL;
    saved_filename1 = tomoyo_save_name(filename1);
    saved_filename2 = tomoyo_save_name(filename2);
    - if (!saved_filename1 || !saved_filename2)
    + if (!saved_filename1 || !saved_filename2) {
    + tomoyo_del_name(saved_filename1);
    + tomoyo_del_name(saved_filename2);
    return -ENOMEM;
    + }
    /***** EXCLUSIVE SECTION START *****/
    - down_write(&tomoyo_domain_acl_info_list_lock);
    + down_write(&tomoyo_policy_lock);
    if (is_delete)
    goto delete;
    list_for_each_entry(ptr, &domain->acl_info_list, list) {
    @@ -862,7 +931,9 @@ static int tomoyo_update_double_path_acl
    goto out;
    acl->perm = perm;
    acl->filename1 = saved_filename1;
    + saved_filename1 = NULL;
    acl->filename2 = saved_filename2;
    + saved_filename2 = NULL;
    list_add_tail(&acl->head.list, &domain->acl_info_list);
    error = 0;
    goto out;
    @@ -883,7 +954,9 @@ static int tomoyo_update_double_path_acl
    break;
    }
    out:
    - up_write(&tomoyo_domain_acl_info_list_lock);
    + tomoyo_del_name(saved_filename1);
    + tomoyo_del_name(saved_filename2);
    + up_write(&tomoyo_policy_lock);
    /***** EXCLUSIVE SECTION END *****/
    return error;
    }
    @@ -929,7 +1002,7 @@ static int tomoyo_check_double_path_acl(

    if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
    return 0;
    - down_read(&tomoyo_domain_acl_info_list_lock);
    + down_read(&tomoyo_policy_lock);
    list_for_each_entry(ptr, &domain->acl_info_list, list) {
    struct tomoyo_double_path_acl_record *acl;
    if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
    @@ -945,7 +1018,7 @@ static int tomoyo_check_double_path_acl(
    error = 0;
    break;
    }
    - up_read(&tomoyo_domain_acl_info_list_lock);
    + up_read(&tomoyo_policy_lock);
    return error;
    }

    @@ -980,8 +1053,12 @@ static int tomoyo_check_single_path_perm
    tomoyo_get_msg(is_enforce), msg, filename->name,
    tomoyo_get_last_name(domain));
    if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
    - const char *name = tomoyo_get_file_pattern(filename)->name;
    - tomoyo_update_single_path_acl(operation, name, domain, false);
    + struct tomoyo_cookie cookie;
    + tomoyo_add_cookie(&cookie, filename);
    + tomoyo_get_file_pattern(&cookie);
    + tomoyo_update_single_path_acl(operation, cookie.u.path->name,
    + domain, false);
    + tomoyo_del_cookie(&cookie);
    }
    if (!is_enforce)
    error = 0;
    @@ -1227,10 +1304,17 @@ int tomoyo_check_2path_perm(struct tomoy
    msg, buf1->name, buf2->name,
    tomoyo_get_last_name(domain));
    if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
    - const char *name1 = tomoyo_get_file_pattern(buf1)->name;
    - const char *name2 = tomoyo_get_file_pattern(buf2)->name;
    - tomoyo_update_double_path_acl(operation, name1, name2, domain,
    + struct tomoyo_cookie cookie1;
    + struct tomoyo_cookie cookie2;
    + tomoyo_add_cookie(&cookie1, buf1);
    + tomoyo_add_cookie(&cookie2, buf2);
    + tomoyo_get_file_pattern(&cookie1);
    + tomoyo_get_file_pattern(&cookie2);
    + tomoyo_update_double_path_acl(operation, cookie1.u.path->name,
    + cookie2.u.path->name, domain,
    false);
    + tomoyo_del_cookie(&cookie1);
    + tomoyo_del_cookie(&cookie2);
    }
    out:
    tomoyo_free(buf1);
    --- security-testing-2.6.git.orig/security/tomoyo/realpath.c
    +++ security-testing-2.6.git/security/tomoyo/realpath.c
    @@ -194,68 +194,51 @@ char *tomoyo_realpath_nofollow(const cha
    }

    /* Memory allocated for non-string data. */
    -static unsigned int tomoyo_allocated_memory_for_elements;
    +static atomic_t tomoyo_allocated_memory_for_elements;
    /* Quota for holding non-string data. */
    static unsigned int tomoyo_quota_for_elements;

    /**
    - * tomoyo_alloc_element - Allocate permanent memory for structures.
    + * tomoyo_alloc_element - Allocate memory for structures.
    *
    * @size: Size in bytes.
    *
    * Returns pointer to allocated memory on success, NULL otherwise.
    *
    - * Memory has to be zeroed.
    - * The RAM is chunked, so NEVER try to kfree() the returned pointer.
    + * Memory are zeroed.
    */
    void *tomoyo_alloc_element(const unsigned int size)
    {
    - static char *buf;
    - static DEFINE_MUTEX(lock);
    - static unsigned int buf_used_len = PATH_MAX;
    - char *ptr = NULL;
    - /*Assumes sizeof(void *) >= sizeof(long) is true. */
    - const unsigned int word_aligned_size
    - = roundup(size, max(sizeof(void *), sizeof(long)));
    - if (word_aligned_size > PATH_MAX)
    - return NULL;
    - /***** EXCLUSIVE SECTION START *****/
    - mutex_lock(&lock);
    - if (buf_used_len + word_aligned_size > PATH_MAX) {
    - if (!tomoyo_quota_for_elements ||
    - tomoyo_allocated_memory_for_elements
    - + PATH_MAX <= tomoyo_quota_for_elements)
    - ptr = kzalloc(PATH_MAX, GFP_KERNEL);
    - if (!ptr) {
    - printk(KERN_WARNING "ERROR: Out of memory "
    - "for tomoyo_alloc_element().\n");
    - if (!tomoyo_policy_loaded)
    - panic("MAC Initialization failed.\n");
    - } else {
    - buf = ptr;
    - tomoyo_allocated_memory_for_elements += PATH_MAX;
    - buf_used_len = word_aligned_size;
    - ptr = buf;
    - }
    - } else if (word_aligned_size) {
    - int i;
    - ptr = buf + buf_used_len;
    - buf_used_len += word_aligned_size;
    - for (i = 0; i < word_aligned_size; i++) {
    - if (!ptr[i])
    - continue;
    - printk(KERN_ERR "WARNING: Reserved memory was tainted! "
    - "The system might go wrong.\n");
    - ptr[i] = '\0';
    - }
    + char *ptr = kzalloc(size, GFP_KERNEL);
    + int len = ptr ? ksize(ptr) : 0;
    + atomic_add(len, &tomoyo_allocated_memory_for_elements);
    + if (!len ||
    + (tomoyo_quota_for_elements &&
    + atomic_read(&tomoyo_allocated_memory_for_elements)
    + > tomoyo_quota_for_elements)) {
    + kfree(ptr);
    + ptr = NULL;
    + atomic_sub(len, &tomoyo_allocated_memory_for_elements);
    + printk(KERN_WARNING "ERROR: Out of memory for %s().\n",
    + __func__);
    + if (!tomoyo_policy_loaded)
    + panic("MAC Initialization failed.\n");
    }
    - mutex_unlock(&lock);
    - /***** EXCLUSIVE SECTION END *****/
    return ptr;
    }

    +void tomoyo_free_element(void *ptr)
    +{
    + int len;
    + if (!ptr)
    + return;
    + len = ksize(ptr);
    + kfree(ptr);
    + atomic_sub(len, &tomoyo_allocated_memory_for_elements);
    +}
    +
    /* Memory allocated for string data in bytes. */
    -static unsigned int tomoyo_allocated_memory_for_savename;
    +static atomic_t tomoyo_allocated_memory_for_savename;
    /* Quota for holding string data in bytes. */
    static unsigned int tomoyo_quota_for_savename;

    @@ -269,44 +252,27 @@ static unsigned int tomoyo_quota_for_sav
    /* Structure for string data. */
    struct tomoyo_name_entry {
    struct list_head list;
    + atomic_t users;
    struct tomoyo_path_info entry;
    };

    -/* Structure for available memory region. */
    -struct tomoyo_free_memory_block_list {
    - struct list_head list;
    - char *ptr; /* Pointer to a free area. */
    - int len; /* Length of the area. */
    -};
    -
    -/*
    - * The list for "struct tomoyo_name_entry".
    - *
    - * This list is updated only inside tomoyo_save_name(), thus
    - * no global mutex exists.
    - */
    +/* The list for "struct tomoyo_name_entry". */
    static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
    +static DEFINE_MUTEX(tomoyo_name_list_lock);

    /**
    - * tomoyo_save_name - Allocate permanent memory for string data.
    + * tomoyo_save_name - Allocate shared memory for string data.
    *
    - * @name: The string to store into the permernent memory.
    + * @name: The string to add or find.
    *
    * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
    - *
    - * The RAM is shared, so NEVER try to modify or kfree() the returned name.
    */
    const struct tomoyo_path_info *tomoyo_save_name(const char *name)
    {
    - static LIST_HEAD(fmb_list);
    - static DEFINE_MUTEX(lock);
    struct tomoyo_name_entry *ptr;
    unsigned int hash;
    - /* fmb contains available size in bytes.
    - fmb is removed from the fmb_list when fmb->len becomes 0. */
    - struct tomoyo_free_memory_block_list *fmb;
    int len;
    - char *cp;
    + int allocated_len;

    if (!name)
    return NULL;
    @@ -318,74 +284,89 @@ const struct tomoyo_path_info *tomoyo_sa
    }
    hash = full_name_hash((const unsigned char *) name, len - 1);
    /***** EXCLUSIVE SECTION START *****/
    - mutex_lock(&lock);
    + mutex_lock(&tomoyo_name_list_lock);
    list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH],
    - list) {
    - if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
    - goto out;
    - }
    - list_for_each_entry(fmb, &fmb_list, list) {
    - if (len <= fmb->len)
    - goto ready;
    + list) {
    + if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
    + continue;
    + atomic_inc(&ptr->users);
    + goto out;
    }
    - if (!tomoyo_quota_for_savename ||
    - tomoyo_allocated_memory_for_savename + PATH_MAX
    - <= tomoyo_quota_for_savename)
    - cp = kzalloc(PATH_MAX, GFP_KERNEL);
    - else
    - cp = NULL;
    - fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
    - if (!cp || !fmb) {
    - kfree(cp);
    - kfree(fmb);
    - printk(KERN_WARNING "ERROR: Out of memory "
    - "for tomoyo_save_name().\n");
    + ptr = kmalloc(sizeof(*ptr) + len, GFP_KERNEL);
    + allocated_len = ptr ? ksize(ptr) : 0;
    + if (!allocated_len ||
    + (tomoyo_quota_for_savename &&
    + atomic_read(&tomoyo_allocated_memory_for_savename)
    + + allocated_len > tomoyo_quota_for_savename)) {
    + kfree(ptr);
    + ptr = NULL;
    + printk(KERN_WARNING "ERROR: Out of memory for %s().\n",
    + __func__);
    if (!tomoyo_policy_loaded)
    panic("MAC Initialization failed.\n");
    - ptr = NULL;
    goto out;
    }
    - tomoyo_allocated_memory_for_savename += PATH_MAX;
    - list_add(&fmb->list, &fmb_list);
    - fmb->ptr = cp;
    - fmb->len = PATH_MAX;
    - ready:
    - ptr = tomoyo_alloc_element(sizeof(*ptr));
    - if (!ptr)
    - goto out;
    - ptr->entry.name = fmb->ptr;
    - memmove(fmb->ptr, name, len);
    + atomic_add(allocated_len, &tomoyo_allocated_memory_for_savename);
    + ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
    + memmove((char *) ptr->entry.name, name, len);
    + atomic_set(&ptr->users, 1);
    tomoyo_fill_path_info(&ptr->entry);
    - fmb->ptr += len;
    - fmb->len -= len;
    list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
    - if (fmb->len == 0) {
    - list_del(&fmb->list);
    - kfree(fmb);
    - }
    out:
    - mutex_unlock(&lock);
    + mutex_unlock(&tomoyo_name_list_lock);
    /***** EXCLUSIVE SECTION END *****/
    return ptr ? &ptr->entry : NULL;
    }

    /**
    + * tomoyo_del_name - Delete shared memory for string data.
    + *
    + * @name: Pointer to "struct tomoyo_path_info".
    + */
    +void tomoyo_del_name(const struct tomoyo_path_info *name)
    +{
    + struct tomoyo_name_entry *ptr;
    +
    + if (!name)
    + return;
    + /***** EXCLUSIVE SECTION START *****/
    + mutex_lock(&tomoyo_name_list_lock);
    + list_for_each_entry(ptr, &tomoyo_name_list[name->hash %
    + TOMOYO_MAX_HASH], list) {
    + if (tomoyo_pathcmp(name, &ptr->entry))
    + continue;
    + if (atomic_dec_and_test(&ptr->users)) {
    + int len = ksize(ptr);
    + list_del(&ptr->list);
    + kfree(ptr);
    + atomic_sub(len, &tomoyo_allocated_memory_for_savename);
    + }
    + break;
    + }
    + mutex_unlock(&tomoyo_name_list_lock);
    + /***** EXCLUSIVE SECTION END *****/
    +}
    +
    +/**
    * tomoyo_realpath_init - Initialize realpath related code.
    */
    void __init tomoyo_realpath_init(void)
    {
    int i;
    + struct tomoyo_cookie cookie;

    BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
    for (i = 0; i < TOMOYO_MAX_HASH; i++)
    INIT_LIST_HEAD(&tomoyo_name_list[i]);
    INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
    + /* No lock because this domain is not deletable. */
    tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME);
    list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
    - down_read(&tomoyo_domain_list_lock);
    - if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
    + down_read(&tomoyo_policy_lock);
    + if (!tomoyo_find_domain(TOMOYO_ROOT_NAME, &cookie) ||
    + cookie.u.domain != &tomoyo_kernel_domain)
    panic("Can't register tomoyo_kernel_domain");
    - up_read(&tomoyo_domain_list_lock);
    + up_read(&tomoyo_policy_lock);
    }

    /* Memory allocated for temporary purpose. */
    @@ -432,9 +413,9 @@ int tomoyo_read_memory_counter(struct to
    {
    if (!head->read_eof) {
    const unsigned int shared
    - = tomoyo_allocated_memory_for_savename;
    + = atomic_read(&tomoyo_allocated_memory_for_savename);
    const unsigned int private
    - = tomoyo_allocated_memory_for_elements;
    + = atomic_read(&tomoyo_allocated_memory_for_elements);
    const unsigned int dynamic
    = atomic_read(&tomoyo_dynamic_memory_size);
    char buffer[64];
    @@ -480,3 +461,64 @@ int tomoyo_write_memory_quota(struct tom
    tomoyo_quota_for_elements = size;
    return 0;
    }
    +
    +/* List of pointers referenced by cookies. */
    +static LIST_HEAD(tomoyo_cookie_list);
    +static DEFINE_RWLOCK(tomoyo_cookie_list_lock);
    +
    +/**
    + * tomoyo_add_cookie - Add a cookie to cookie list.
    + *
    + * @cookie: Pointer to "struct tomoyo_cookie".
    + * @ptr: Pointer to assign.
    + */
    +void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr)
    +{
    + unsigned long flags;
    + if (!cookie)
    + return;
    + tomoyo_update_cookie(cookie, ptr);
    + write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
    + list_add_tail(&cookie->list, &tomoyo_cookie_list);
    + write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
    +}
    +
    +/**
    + * tomoyo_del_cookie - Delete a cookie from cookie list.
    + *
    + * @cookie: Pointer to "struct tomoyo_cookie".
    + */
    +void tomoyo_del_cookie(struct tomoyo_cookie *cookie)
    +{
    + unsigned long flags;
    + if (!cookie)
    + return;
    + write_lock_irqsave(&tomoyo_cookie_list_lock, flags);
    + list_del(&cookie->list);
    + write_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
    +}
    +
    +/**
    + * tomoyo_used_by_cookie - Check whether the given pointer is referenced by a cookie or not.
    + *
    + * @ptr: Pointer to check.
    + *
    + * Returns true if @ptr is in use, false otherwise.
    + *
    + * Caller must hold tomoyo_policy_lock for writing.
    + */
    +bool tomoyo_used_by_cookie(const void *ptr)
    +{
    + unsigned long flags;
    + struct tomoyo_cookie *cookie;
    + bool in_use = false;
    + read_lock_irqsave(&tomoyo_cookie_list_lock, flags);
    + list_for_each_entry(cookie, &tomoyo_cookie_list, list) {
    + if (ptr != cookie->u.ptr)
    + continue;
    + in_use = true;
    + break;
    + }
    + read_unlock_irqrestore(&tomoyo_cookie_list_lock, flags);
    + return in_use;
    +}
    --- security-testing-2.6.git.orig/security/tomoyo/realpath.h
    +++ security-testing-2.6.git/security/tomoyo/realpath.h
    @@ -36,18 +36,6 @@ char *tomoyo_realpath_nofollow(const cha
    /* Same with tomoyo_realpath() except that the pathname is already solved. */
    char *tomoyo_realpath_from_path(struct path *path);

    -/*
    - * Allocate memory for ACL entry.
    - * The RAM is chunked, so NEVER try to kfree() the returned pointer.
    - */
    -void *tomoyo_alloc_element(const unsigned int size);
    -
    -/*
    - * Keep the given name on the RAM.
    - * The RAM is shared, so NEVER try to modify or kfree() the returned name.
    - */
    -const struct tomoyo_path_info *tomoyo_save_name(const char *name);
    -
    /* Allocate memory for temporary use (e.g. permission checks). */
    void *tomoyo_alloc(const size_t size);

    @@ -63,4 +51,35 @@ int tomoyo_write_memory_quota(struct tom
    /* Initialize realpath related code. */
    void __init tomoyo_realpath_init(void);

    +/* Allocate memory for ACL entry. */
    +void *tomoyo_alloc_element(const unsigned int size);
    +/* Delete memory for ACL entry. */
    +void tomoyo_free_element(void *ptr);
    +
    +/* Allocate memory for the given name. */
    +const struct tomoyo_path_info *tomoyo_save_name(const char *name);
    +/* Delete memory for the given name. */
    +void tomoyo_del_name(const struct tomoyo_path_info *name);
    +
    +/* Add a cookie to cookie list. */
    +void tomoyo_add_cookie(struct tomoyo_cookie *cookie, const void *ptr);
    +/**
    + * tomoyo_update_cookie - Assign the given pointer to a cookie.
    + *
    + * @cookie: Pointer to "struct tomoyo_cookie".
    + * @ptr: Pointer to assign.
    + *
    + * Caller must hold tomoyo_policy_lock for writing unless @ptr is NULL or
    + * @ptr is already in cookie list.
    + */
    +static inline void tomoyo_update_cookie(struct tomoyo_cookie *cookie,
    + const void *ptr)
    +{
    + cookie->u.ptr = ptr;
    +}
    +/* Delete a cookie from cookie list. */
    +void tomoyo_del_cookie(struct tomoyo_cookie *cookie);
    +/* Check whether the given pointer is referenced by a cookie or not. */
    +bool tomoyo_used_by_cookie(const void *ptr);
    +
    #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */
    --- security-testing-2.6.git.orig/security/tomoyo/tomoyo.c
    +++ security-testing-2.6.git/security/tomoyo/tomoyo.c
    @@ -17,14 +17,23 @@
    static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
    gfp_t gfp)
    {
    - /*
    - * Since "struct tomoyo_domain_info *" is a sharable pointer,
    - * we don't need to duplicate.
    - */
    - new->security = old->security;
    + struct tomoyo_cookie *cookie = kzalloc(sizeof(*cookie), gfp);
    +
    + if (!cookie)
    + return -ENOMEM;
    + tomoyo_add_cookie(cookie,
    + ((struct tomoyo_cookie *) old->security)->u.ptr);
    + new->security = cookie;
    return 0;
    }

    +static void tomoyo_cred_free(struct cred *cred)
    +{
    + struct tomoyo_cookie *cookie = cred->security;
    + tomoyo_del_cookie(cookie);
    + kfree(cookie);
    +}
    +
    static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
    {
    /*
    @@ -43,26 +52,21 @@ static int tomoyo_bprm_set_creds(struct
    * Tell tomoyo_bprm_check_security() is called for the first time of an
    * execve operation.
    */
    - bprm->cred->security = NULL;
    + ((struct tomoyo_cookie *) bprm->cred->security)->u.domain = NULL;
    return 0;
    }

    static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
    {
    - struct tomoyo_domain_info *domain = bprm->cred->security;
    + struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
    + bprm->cred->security)->u.domain;

    /*
    * Execute permission is checked against pathname passed to do_execve()
    * using current domain.
    */
    - if (!domain) {
    - struct tomoyo_domain_info *next_domain = NULL;
    - int retval = tomoyo_find_next_domain(bprm, &next_domain);
    -
    - if (!retval)
    - bprm->cred->security = next_domain;
    - return retval;
    - }
    + if (!domain)
    + return tomoyo_find_next_domain(bprm);
    /*
    * Read permission is checked against interpreters using next domain.
    * '1' is the result of open_to_namei_flags(O_RDONLY).
    @@ -259,6 +263,7 @@ static int tomoyo_dentry_open(struct fil
    static struct security_operations tomoyo_security_ops = {
    .name = "tomoyo",
    .cred_prepare = tomoyo_cred_prepare,
    + .cred_free = tomoyo_cred_free,
    .bprm_set_creds = tomoyo_bprm_set_creds,
    .bprm_check_security = tomoyo_bprm_check_security,
    #ifdef CONFIG_SYSCTL
    @@ -279,6 +284,7 @@ static struct security_operations tomoyo
    static int __init tomoyo_init(void)
    {
    struct cred *cred = (struct cred *) current_cred();
    + struct tomoyo_cookie *cookie;

    if (!security_module_enable(&tomoyo_security_ops))
    return 0;
    @@ -286,7 +292,9 @@ static int __init tomoyo_init(void)
    if (register_security(&tomoyo_security_ops))
    panic("Failure registering TOMOYO Linux");
    printk(KERN_INFO "TOMOYO Linux initialized\n");
    - cred->security = &tomoyo_kernel_domain;
    + cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
    + tomoyo_add_cookie(cookie, &tomoyo_kernel_domain);
    + cred->security = cookie;
    tomoyo_realpath_init();
    return 0;
    }
    --- security-testing-2.6.git.orig/security/tomoyo/tomoyo.h
    +++ security-testing-2.6.git/security/tomoyo/tomoyo.h
    @@ -33,8 +33,7 @@ int tomoyo_check_2path_perm(struct tomoy
    struct path *path2);
    int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
    struct file *filp);
    -int tomoyo_find_next_domain(struct linux_binprm *bprm,
    - struct tomoyo_domain_info **next_domain);
    +int tomoyo_find_next_domain(struct linux_binprm *bprm);

    /* Index numbers for Access Controls. */

    @@ -85,18 +84,14 @@ int tomoyo_find_next_domain(struct linux

    extern struct tomoyo_domain_info tomoyo_kernel_domain;

    -static inline struct tomoyo_domain_info *tomoyo_domain(void)
    -{
    - return current_cred()->security;
    -}
    -
    -/* Caller holds tasklist_lock spinlock. */
    +/* Caller calls rcu_read_lock()/rcu_read_unlock(). */
    static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
    *task)
    {
    /***** CRITICAL SECTION START *****/
    const struct cred *cred = get_task_cred(task);
    - struct tomoyo_domain_info *domain = cred->security;
    + struct tomoyo_domain_info *domain = ((struct tomoyo_cookie *)
    + cred->security)->u.domain;

    put_cred(cred);
    return domain;

    \
     
     \ /
      Last update: 2009-05-07 13:45    [W:0.160 / U:1.324 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site