[PATCH 5/5] TOMOYO: Add refcounter and garbage collector.

From: Tetsuo Handa
Date: Mon Jun 01 2009 - 21:47:50 EST


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.

Approach:

Define a structure

struct tomoyo_entry {
struct list_head list;
atomic_t users;
};

and replace "struct list_head" with "struct tomoyo_entry".

Get a reference by calling

void tomoyo_get_ref(struct list_head *item)

before releasing a lock and drop a reference by calling

void tomoyo_put_ref(struct list_head *item)

after obtaining a lock.

Memory Management Rules:

When /sys/kernel/security/tomoyo/ interface opened for writing is closed,
garbage collector functions are called. The garbage collector functions take
appropriate locks and remove elements if that element has is_deleted flag set
and that element's refcounter is 0.

Since strings are likely referenced by multiple list elements, this patch
assigns a refcounter to each string.
The garbage collector function releases memory of the string if the string's
refcounter becomes 0.

Signed-off-by: Kentaro Takeda <takedakn@xxxxxxxxxxxxx>
Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Toshiharu Harada <haradats@xxxxxxxxxxxxx>
---
security/tomoyo/common.c | 313 +++++++++++++++++++++++++++++++++++----------
security/tomoyo/common.h | 58 +++++---
security/tomoyo/domain.c | 277 ++++++++++++++++++++-------------------
security/tomoyo/file.c | 199 ++++++++++++++++++++++------
security/tomoyo/realpath.c | 57 ++++++--
security/tomoyo/realpath.h | 7 -
security/tomoyo/tomoyo.c | 28 ++--
security/tomoyo/tomoyo.h | 3
8 files changed, 650 insertions(+), 292 deletions(-)

--- security-testing-2.6.git.orig/security/tomoyo/common.c
+++ security-testing-2.6.git/security/tomoyo/common.c
@@ -327,10 +327,9 @@ bool tomoyo_is_domain_def(const unsigned
*
* @domainname: The domainname to find.
*
- * Caller must call down_read(&tomoyo_domain_list_lock); or
- * down_write(&tomoyo_domain_list_lock); .
- *
* Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ *
+ * Caller must call down_read(&tomoyo_domain_list_lock);.
*/
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
{
@@ -339,7 +338,7 @@ struct tomoyo_domain_info *tomoyo_find_d

name.name = domainname;
tomoyo_fill_path_info(&name);
- list_for_each_entry(domain, &tomoyo_domain_list, list) {
+ list_for_each_entry(domain, &tomoyo_domain_list, entry.list) {
if (!domain->is_deleted &&
!tomoyo_pathcmp(&name, domain->domainname))
return domain;
@@ -788,7 +787,7 @@ bool tomoyo_domain_quota_is_ok(struct to
return true;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_acl_info_list_lock);
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
if (ptr->type & TOMOYO_ACL_DELETED)
continue;
switch (tomoyo_acl_type2(ptr)) {
@@ -889,6 +888,9 @@ static struct tomoyo_profile *tomoyo_fin
return ptr;
}

+/* Lock for protecting profile->comment. */
+static DEFINE_MUTEX(tomoyo_profile_comment_lock);
+
/**
* tomoyo_write_profile - Write to profile table.
*
@@ -923,8 +925,12 @@ static int tomoyo_write_profile(struct t
const struct tomoyo_path_info *new_comment
= tomoyo_get_name(cp + 1);
const struct tomoyo_path_info *old_comment;
+ /***** EXCLUSIVE SECTION START *****/
+ mutex_lock(&tomoyo_profile_comment_lock);
old_comment = profile->comment;
profile->comment = new_comment;
+ mutex_unlock(&tomoyo_profile_comment_lock);
+ /***** EXCLUSIVE SECTION END *****/
tomoyo_put_name(old_comment);
return 0;
}
@@ -983,9 +989,15 @@ 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;
+ /***** EXCLUSIVE SECTION START *****/
+ mutex_lock(&tomoyo_profile_comment_lock);
+ done = tomoyo_io_printf(head, "%u-COMMENT=%s\n",
+ index, profile->comment ?
+ profile->comment->name : "");
+ mutex_unlock(&tomoyo_profile_comment_lock);
+ /***** EXCLUSIVE SECTION END *****/
+ if (!done)
break;
continue;
}
@@ -1021,7 +1033,7 @@ static int tomoyo_read_profile(struct to

/* Structure for policy manager. */
struct tomoyo_policy_manager_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
/* A path to program or a domainname. */
const struct tomoyo_path_info *manager;
bool is_domain; /* True if manager is a domainname. */
@@ -1064,7 +1076,7 @@ static int tomoyo_update_manager_entry(c
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_policy_manager_list_lock);
- list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+ list_for_each_entry(ptr, &tomoyo_policy_manager_list, entry.list) {
if (ptr->manager != saved_manager)
continue;
ptr->is_deleted = is_delete;
@@ -1073,8 +1085,10 @@ static int tomoyo_update_manager_entry(c
}
if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
new_entry->manager = saved_manager;
+ saved_manager = NULL;
new_entry->is_domain = is_domain;
- list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
+ list_add_tail(&new_entry->entry.list,
+ &tomoyo_policy_manager_list);
new_entry = NULL;
error = 0;
}
@@ -1085,6 +1099,32 @@ static int tomoyo_update_manager_entry(c
}

/**
+ * tomoyo_cleanup_manager - Clean up deleted "struct tomoyo_policy_manager_entry".
+ */
+static void tomoyo_cleanup_manager(void)
+{
+ struct tomoyo_policy_manager_entry *ptr;
+ struct tomoyo_policy_manager_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_policy_manager_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_policy_manager_list,
+ entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_policy_manager_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->manager);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_write_manager_policy - Write manager policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -1119,17 +1159,19 @@ static int tomoyo_read_manager_policy(st
return 0;
/***** READER SECTION START *****/
down_read(&tomoyo_policy_manager_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2,
&tomoyo_policy_manager_list) {
struct tomoyo_policy_manager_entry *ptr;
ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
- list);
+ entry.list);
if (ptr->is_deleted)
continue;
done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_policy_manager_list_lock);
/***** READER SECTION END *****/
head->read_eof = done;
@@ -1156,7 +1198,7 @@ static bool tomoyo_is_policy_manager(voi
return false;
/***** READER SECTION START *****/
down_read(&tomoyo_policy_manager_list_lock);
- list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+ list_for_each_entry(ptr, &tomoyo_policy_manager_list, entry.list) {
if (!ptr->is_deleted && ptr->is_domain
&& !tomoyo_pathcmp(domainname, ptr->manager)) {
found = true;
@@ -1172,7 +1214,7 @@ static bool tomoyo_is_policy_manager(voi
return false;
/***** READER SECTION START *****/
down_read(&tomoyo_policy_manager_list_lock);
- list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
+ list_for_each_entry(ptr, &tomoyo_policy_manager_list, entry.list) {
if (!ptr->is_deleted && !ptr->is_domain
&& !strcmp(exe, ptr->manager->name)) {
found = true;
@@ -1205,9 +1247,15 @@ static bool tomoyo_is_policy_manager(voi
static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
const char *data)
{
+ bool result = false;
unsigned int pid;
struct tomoyo_domain_info *domain = NULL;

+ /***** READER SECTION START *****/
+ down_read(&tomoyo_domain_list_lock);
+ tomoyo_put_ref(head->write_var1);
+ tomoyo_put_ref(head->read_var1);
+ tomoyo_put_ref(head->read_var2);
if (sscanf(data, "pid=%u", &pid) == 1) {
struct task_struct *p;
/***** CRITICAL SECTION START *****/
@@ -1218,19 +1266,15 @@ static bool tomoyo_is_select_one(struct
read_unlock(&tasklist_lock);
/***** CRITICAL SECTION END *****/
} else if (!strncmp(data, "domain=", 7)) {
- if (tomoyo_is_domain_def(data + 7)) {
- /***** READER SECTION START *****/
- down_read(&tomoyo_domain_list_lock);
+ if (tomoyo_is_domain_def(data + 7))
domain = tomoyo_find_domain(data + 7);
- up_read(&tomoyo_domain_list_lock);
- /***** READER SECTION END *****/
- }
} else
- return false;
- head->write_var1 = domain;
+ goto out;
+ result = true;
+ head->write_var1 = domain ? &domain->entry.list : NULL;
/* Accessing read_buf is safe because head->io_sem is held. */
if (!head->read_buf)
- return true; /* Do nothing if open(O_WRONLY). */
+ goto out; /* Do nothing if open(O_WRONLY). */
head->read_avail = 0;
tomoyo_io_printf(head, "# select %s\n", data);
head->read_single_domain = true;
@@ -1238,22 +1282,62 @@ static bool tomoyo_is_select_one(struct
if (domain) {
struct tomoyo_domain_info *d;
head->read_var1 = NULL;
- /***** READER SECTION START *****/
- down_read(&tomoyo_domain_list_lock);
- list_for_each_entry(d, &tomoyo_domain_list, list) {
+ list_for_each_entry(d, &tomoyo_domain_list, entry.list) {
if (d == domain)
break;
- head->read_var1 = &d->list;
+ head->read_var1 = &d->entry.list;
}
- up_read(&tomoyo_domain_list_lock);
- /***** READER SECTION END *****/
head->read_var2 = NULL;
head->read_bit = 0;
head->read_step = 0;
if (domain->is_deleted)
tomoyo_io_printf(head, "# This is a deleted domain.\n");
}
- return true;
+ out:
+ tomoyo_get_ref(head->read_var2);
+ tomoyo_get_ref(head->read_var1);
+ tomoyo_get_ref(head->write_var1);
+ up_read(&tomoyo_domain_list_lock);
+ /***** READER SECTION END *****/
+ return result;
+}
+
+/**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ *
+ * Returns 0.
+ *
+ * Caller must call down_read(&tomoyo_domain_list_lock);.
+ */
+static int tomoyo_delete_domain(char *domainname)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_path_info name;
+
+ up_read(&tomoyo_domain_list_lock);
+ /***** READER SECTION END *****/
+ name.name = domainname;
+ tomoyo_fill_path_info(&name);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_domain_list_lock);
+ /* Is there an active domain? */
+ list_for_each_entry(domain, &tomoyo_domain_list, entry.list) {
+ /* Never delete tomoyo_kernel_domain */
+ if (domain == &tomoyo_kernel_domain)
+ continue;
+ if (domain->is_deleted ||
+ tomoyo_pathcmp(domain->domainname, &name))
+ continue;
+ domain->is_deleted = true;
+ break;
+ }
+ up_write(&tomoyo_domain_list_lock);
+ /***** WRITER SECTION END *****/
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_domain_list_lock);
+ return 0;
}

/**
@@ -1266,10 +1350,13 @@ 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
+ = container_of(head->write_var1, struct tomoyo_domain_info,
+ entry.list);
bool is_delete = false;
bool is_select = false;
unsigned int profile;
+ int error = 0;

if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE))
is_delete = true;
@@ -1281,35 +1368,31 @@ static int tomoyo_write_domain_policy(st
if (!tomoyo_is_policy_manager())
return -EPERM;
if (tomoyo_is_domain_def(data)) {
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_domain_list_lock);
+ tomoyo_put_ref(head->write_var1);
domain = NULL;
if (is_delete)
tomoyo_delete_domain(data);
- else if (is_select) {
- /***** READER SECTION START *****/
- down_read(&tomoyo_domain_list_lock);
+ else if (is_select)
domain = tomoyo_find_domain(data);
- up_read(&tomoyo_domain_list_lock);
- /***** READER SECTION END *****/
- } else
+ else
domain = tomoyo_find_or_assign_new_domain(data, 0);
- head->write_var1 = domain;
- return 0;
- }
- if (!domain)
- return -EINVAL;
-
- if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
- && profile < TOMOYO_MAX_PROFILES) {
+ head->write_var1 = domain ? &domain->entry.list : NULL;
+ tomoyo_get_ref(head->write_var1);
+ up_read(&tomoyo_domain_list_lock);
+ /***** READER SECTION END *****/
+ } else if (!domain)
+ error = -EINVAL;
+ else if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
+ && profile < TOMOYO_MAX_PROFILES) {
if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
domain->profile = (u8) profile;
- return 0;
- }
- if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
- tomoyo_set_domain_flag(domain, is_delete,
- TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
- return 0;
- }
- return tomoyo_write_file_policy(data, domain, is_delete);
+ } else if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
+ domain->ignore_global_allow_read = !is_delete;
+ } else
+ error = tomoyo_write_file_policy(data, domain, is_delete);
+ return error;
}

/**
@@ -1448,12 +1531,16 @@ static int tomoyo_read_domain_policy(str
head->read_step = 1;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_list_lock);
+ down_read(&tomoyo_domain_acl_info_list_lock);
+ tomoyo_put_ref(head->read_var1);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
struct tomoyo_domain_info *domain;
const char *quota_exceeded = "";
const char *transition_failed = "";
const char *ignore_global_allow_read = "";
- domain = list_entry(dpos, struct tomoyo_domain_info, list);
+ domain = list_entry(dpos, struct tomoyo_domain_info,
+ entry.list);
if (head->read_step != 1)
goto acl_loop;
if (domain->is_deleted && !head->read_single_domain)
@@ -1461,10 +1548,9 @@ static int tomoyo_read_domain_policy(str
/* Print domainname and flags. */
if (domain->quota_warned)
quota_exceeded = "quota_exceeded\n";
- if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED)
+ if (domain->domain_transition_failed)
transition_failed = "transition_failed\n";
- if (domain->flags &
- TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
+ if (domain->ignore_global_allow_read)
ignore_global_allow_read
= TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE
@@ -1480,19 +1566,15 @@ acl_loop:
if (head->read_step == 3)
goto tail_mark;
/* Print ACL entries in the domain. */
- /***** READER SECTION START *****/
- down_read(&tomoyo_domain_acl_info_list_lock);
list_for_each_cookie(apos, head->read_var2,
&domain->acl_info_list) {
struct tomoyo_acl_info *ptr
= list_entry(apos, struct tomoyo_acl_info,
- list);
+ entry.list);
done = tomoyo_print_entry(head, ptr);
if (!done)
break;
}
- up_read(&tomoyo_domain_acl_info_list_lock);
- /***** READER SECTION END *****/
if (!done)
break;
head->read_step = 3;
@@ -1504,6 +1586,9 @@ tail_mark:
if (head->read_single_domain)
break;
}
+ tomoyo_get_ref(head->read_var2);
+ tomoyo_get_ref(head->read_var1);
+ up_read(&tomoyo_domain_acl_info_list_lock);
up_read(&tomoyo_domain_list_lock);
/***** READER SECTION END *****/
head->read_eof = done;
@@ -1511,6 +1596,71 @@ tail_mark:
}

/**
+ * tomoyo_cleanup_domain_policy - Clean up deleted domain policy.
+ */
+static void tomoyo_cleanup_domain_policy(void)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_domain_info *next_domain;
+ struct tomoyo_acl_info *acl;
+ struct tomoyo_acl_info *next_acl;
+ LIST_HEAD(q_domain);
+ LIST_HEAD(q_acl);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_domain_list_lock);
+ list_for_each_entry_safe(domain, next_domain, &tomoyo_domain_list,
+ entry.list) {
+ const bool can_delete_domain = domain->is_deleted &&
+ !atomic_read(&domain->entry.users);
+ if (can_delete_domain) {
+ list_for_each_entry(acl, &domain->acl_info_list,
+ entry.list)
+ acl->type |= TOMOYO_ACL_DELETED;
+ }
+ list_for_each_entry_safe(acl, next_acl, &domain->acl_info_list,
+ entry.list) {
+ if (!(acl->type & TOMOYO_ACL_DELETED)
+ || atomic_read(&acl->entry.users))
+ continue;
+ list_del(&acl->entry.list);
+ list_add(&acl->entry.list, &q_acl);
+ }
+ if (can_delete_domain && list_empty(&domain->acl_info_list)) {
+ list_del(&domain->entry.list);
+ list_add(&domain->entry.list, &q_domain);
+ }
+ }
+ up_write(&tomoyo_domain_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(acl, next_acl, &q_acl, entry.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_put_name(acl1->filename);
+ break;
+ case TOMOYO_TYPE_DOUBLE_PATH_ACL:
+ acl2 = container_of(acl,
+ struct tomoyo_double_path_acl_record,
+ head);
+ tomoyo_put_name(acl2->filename1);
+ tomoyo_put_name(acl2->filename2);
+ break;
+ }
+ list_del(&acl->entry.list);
+ tomoyo_free_element(acl);
+ }
+ list_for_each_entry_safe(domain, next_domain, &q_domain, entry.list) {
+ tomoyo_put_name(domain->domainname);
+ list_del(&domain->entry.list);
+ tomoyo_free_element(domain);
+ }
+}
+
+/**
* tomoyo_write_domain_profile - Assign profile for specified domain.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -1532,16 +1682,16 @@ static int tomoyo_write_domain_profile(s
if (!cp)
return -EINVAL;
*cp = '\0';
+ if (strict_strtoul(data, 10, &profile) ||
+ profile >= TOMOYO_MAX_PROFILES)
+ return -EINVAL;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_list_lock);
domain = tomoyo_find_domain(cp + 1);
+ if (domain && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
+ domain->profile = (u8) profile;
up_read(&tomoyo_domain_list_lock);
/***** READER SECTION END *****/
- if (strict_strtoul(data, 10, &profile))
- return -EINVAL;
- if (domain && profile < TOMOYO_MAX_PROFILES
- && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
- domain->profile = (u8) profile;
return 0;
}

@@ -1568,9 +1718,10 @@ static int tomoyo_read_domain_profile(st
return 0;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_list_lock);
+ tomoyo_put_ref(head->read_var1);
list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
struct tomoyo_domain_info *domain;
- domain = list_entry(pos, struct tomoyo_domain_info, list);
+ domain = list_entry(pos, struct tomoyo_domain_info, entry.list);
if (domain->is_deleted)
continue;
done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
@@ -1578,6 +1729,7 @@ static int tomoyo_read_domain_profile(st
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var1);
up_read(&tomoyo_domain_list_lock);
/***** READER SECTION END *****/
head->read_eof = done;
@@ -1617,6 +1769,8 @@ static int tomoyo_read_pid(struct tomoyo
const int pid = head->read_step;
struct task_struct *p;
struct tomoyo_domain_info *domain = NULL;
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_domain_list_lock);
/***** CRITICAL SECTION START *****/
read_lock(&tasklist_lock);
p = find_task_by_vpid(pid);
@@ -1627,6 +1781,8 @@ static int tomoyo_read_pid(struct tomoyo
if (domain)
tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
domain->domainname->name);
+ up_read(&tomoyo_domain_list_lock);
+ /***** READER SECTION END *****/
head->read_eof = true;
}
return 0;
@@ -1803,7 +1959,7 @@ void tomoyo_load_policy(const char *file
struct tomoyo_domain_info *domain;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_list_lock);
- list_for_each_entry(domain, &tomoyo_domain_list, list) {
+ list_for_each_entry(domain, &tomoyo_domain_list, entry.list) {
const u8 profile = domain->profile;
if (tomoyo_profile_ptr[profile])
continue;
@@ -1945,6 +2101,10 @@ static int tomoyo_open_control(const u8
}
}
file->private_data = head;
+ /* Get refcount. Though nothing happens. */
+ tomoyo_get_ref(head->write_var1);
+ tomoyo_get_ref(head->read_var1);
+ tomoyo_get_ref(head->read_var2);
/*
* Call the handler now if the file is
* /sys/kernel/security/tomoyo/self_domain
@@ -2062,15 +2222,30 @@ static int tomoyo_write_control(struct f
static int tomoyo_close_control(struct file *file)
{
struct tomoyo_io_buffer *head = file->private_data;
+ const bool is_write = head->write_buf != NULL;

/* Release memory used for policy I/O. */
tomoyo_free(head->read_buf);
head->read_buf = NULL;
tomoyo_free(head->write_buf);
head->write_buf = NULL;
+ /* Put refcount if partially read or written. */
+ tomoyo_put_ref(head->read_var2);
+ tomoyo_put_ref(head->read_var1);
+ tomoyo_put_ref(head->write_var1);
tomoyo_free(head);
head = NULL;
file->private_data = NULL;
+ if (is_write) {
+ tomoyo_cleanup_allow_read();
+ tomoyo_cleanup_file_pattern();
+ tomoyo_cleanup_no_rewrite();
+ tomoyo_cleanup_initializer();
+ tomoyo_cleanup_keep_domain();
+ tomoyo_cleanup_alias();
+ tomoyo_cleanup_manager();
+ tomoyo_cleanup_domain_policy();
+ }
return 0;
}

--- security-testing-2.6.git.orig/security/tomoyo/common.h
+++ security-testing-2.6.git/security/tomoyo/common.h
@@ -23,6 +23,25 @@
#include <linux/mount.h>
#include <linux/list.h>

+struct tomoyo_entry {
+ struct list_head list;
+ atomic_t users;
+};
+
+static inline void tomoyo_get_ref(struct list_head *item)
+{
+ if (item)
+ atomic_dec(&(container_of(item, struct tomoyo_entry,
+ list)->users));
+}
+
+static inline void tomoyo_put_ref(struct list_head *item)
+{
+ if (item)
+ atomic_inc(&(container_of(item, struct tomoyo_entry,
+ list)->users));
+}
+
struct dentry;
struct vfsmount;

@@ -69,7 +88,7 @@ struct tomoyo_path_info_with_data {
* without enlarging their structure size.
*/
struct tomoyo_acl_info {
- struct list_head list;
+ struct tomoyo_entry entry;
/*
* Type of this ACL entry.
*
@@ -83,30 +102,27 @@ struct tomoyo_acl_info {

/* Structure for domain information. */
struct tomoyo_domain_info {
- struct list_head list;
+ struct tomoyo_entry entry;
struct list_head acl_info_list;
/* Name of this domain. Never NULL. */
const struct tomoyo_path_info *domainname;
u8 profile; /* Profile number to use. */
bool is_deleted; /* Delete flag. */
bool quota_warned; /* Quota warnning flag. */
- /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */
- u8 flags;
+ /* Ignore "allow_read" directive in exception policy. */
+ bool ignore_global_allow_read;
+ /*
+ * This domain was unable to create a new domain at
+ * tomoyo_find_next_domain() because the name of the domain to be
+ * created was too long or it could not allocate memory.
+ * More than one process continued execve() without domain transition.
+ */
+ bool domain_transition_failed;
};

/* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256

-/* Ignore "allow_read" directive in exception policy. */
-#define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1
-/*
- * This domain was unable to create a new domain at tomoyo_find_next_domain()
- * because the name of the domain to be created was too long or
- * it could not allocate memory.
- * More than one process continued execve() without domain transition.
- */
-#define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2
-
/*
* Structure for "allow_read/write", "allow_execute", "allow_read",
* "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
@@ -164,7 +180,7 @@ struct tomoyo_io_buffer {
/* Extra variables for reading. */
struct list_head *read_var2;
/* The position currently writing to. */
- struct tomoyo_domain_info *write_var1;
+ struct list_head *write_var1;
/* The step for reading. */
int read_step;
/* Buffer for reading. */
@@ -229,8 +245,6 @@ const char *tomoyo_get_last_name(const s
const char *tomoyo_get_msg(const bool is_enforce);
/* Convert single path operation to operation name. */
const char *tomoyo_sp2keyword(const u8 operation);
-/* Delete a domain. */
-int tomoyo_delete_domain(char *data);
/* Create "alias" entry in exception policy. */
int tomoyo_write_alias_policy(char *data, const bool is_delete);
/*
@@ -270,9 +284,13 @@ unsigned int tomoyo_check_flags(const st
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
/* Run policy loader when /sbin/init starts. */
void tomoyo_load_policy(const char *filename);
-/* Change "struct tomoyo_domain_info"->flags. */
-void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
- const bool is_delete, const u8 flags);
+
+void tomoyo_cleanup_allow_read(void);
+void tomoyo_cleanup_file_pattern(void);
+void tomoyo_cleanup_no_rewrite(void);
+void tomoyo_cleanup_initializer(void);
+void tomoyo_cleanup_keep_domain(void);
+void tomoyo_cleanup_alias(void);

/* strcmp() for "struct tomoyo_path_info" structure. */
static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
--- security-testing-2.6.git.orig/security/tomoyo/domain.c
+++ security-testing-2.6.git/security/tomoyo/domain.c
@@ -25,7 +25,7 @@ DECLARE_RWSEM(tomoyo_domain_list_lock);

/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
struct tomoyo_domain_initializer_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
const struct tomoyo_path_info *domainname; /* This may be NULL */
const struct tomoyo_path_info *program;
bool is_deleted;
@@ -36,7 +36,7 @@ struct tomoyo_domain_initializer_entry {

/* Structure for "keep_domain" and "no_keep_domain" keyword. */
struct tomoyo_domain_keeper_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
const struct tomoyo_path_info *domainname;
const struct tomoyo_path_info *program; /* This may be NULL */
bool is_deleted;
@@ -47,37 +47,13 @@ struct tomoyo_domain_keeper_entry {

/* Structure for "alias" keyword. */
struct tomoyo_alias_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
const struct tomoyo_path_info *original_name;
const struct tomoyo_path_info *aliased_name;
bool is_deleted;
};

/**
- * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- * @flags: Flags to set or clear.
- *
- * Returns nothing.
- */
-void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
- const bool is_delete, const u8 flags)
-{
- /* We need to serialize because this is bitfield operation. */
- static DEFINE_SPINLOCK(lock);
- /***** CRITICAL SECTION START *****/
- spin_lock(&lock);
- if (!is_delete)
- domain->flags |= flags;
- else
- domain->flags &= ~flags;
- spin_unlock(&lock);
- /***** CRITICAL SECTION END *****/
-}
-
-/**
* tomoyo_get_last_name - Get last component of a domainname.
*
* @domain: Pointer to "struct tomoyo_domain_info".
@@ -141,7 +117,7 @@ static int tomoyo_update_domain_initiali
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_domain_initializer_list_lock);
- list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
+ list_for_each_entry(ptr, &tomoyo_domain_initializer_list, entry.list) {
if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
@@ -157,7 +133,7 @@ static int tomoyo_update_domain_initiali
saved_program = NULL;
new_entry->is_not = is_not;
new_entry->is_last_name = is_last_name;
- list_add_tail(&new_entry->list,
+ list_add_tail(&new_entry->entry.list,
&tomoyo_domain_initializer_list);
new_entry = NULL;
error = 0;
@@ -171,6 +147,33 @@ static int tomoyo_update_domain_initiali
}

/**
+ * tomoyo_cleanup_initializer - Clean up deleted "struct tomoyo_domain_initializer_entry".
+ */
+void tomoyo_cleanup_initializer(void)
+{
+ struct tomoyo_domain_initializer_entry *ptr;
+ struct tomoyo_domain_initializer_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_domain_initializer_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_initializer_list,
+ entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_domain_initializer_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->domainname);
+ tomoyo_put_name(ptr->program);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -184,6 +187,7 @@ bool tomoyo_read_domain_initializer_poli

/***** READER SECTION START *****/
down_read(&tomoyo_domain_initializer_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2,
&tomoyo_domain_initializer_list) {
const char *no;
@@ -191,7 +195,7 @@ bool tomoyo_read_domain_initializer_poli
const char *domain = "";
struct tomoyo_domain_initializer_entry *ptr;
ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
- list);
+ entry.list);
if (ptr->is_deleted)
continue;
no = ptr->is_not ? "no_" : "";
@@ -206,6 +210,7 @@ bool tomoyo_read_domain_initializer_poli
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_domain_initializer_list_lock);
/***** READER SECTION END *****/
return done;
@@ -256,7 +261,7 @@ static bool tomoyo_is_domain_initializer

/***** READER SECTION START *****/
down_read(&tomoyo_domain_initializer_list_lock);
- list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
+ list_for_each_entry(ptr, &tomoyo_domain_initializer_list, entry.list) {
if (ptr->is_deleted)
continue;
if (ptr->domainname) {
@@ -329,7 +334,7 @@ static int tomoyo_update_domain_keeper_e
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_domain_keeper_list_lock);
- list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+ list_for_each_entry(ptr, &tomoyo_domain_keeper_list, entry.list) {
if (ptr->is_not != is_not ||
ptr->domainname != saved_domainname ||
ptr->program != saved_program)
@@ -345,7 +350,8 @@ static int tomoyo_update_domain_keeper_e
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);
+ list_add_tail(&new_entry->entry.list,
+ &tomoyo_domain_keeper_list);
new_entry = NULL;
error = 0;
}
@@ -358,6 +364,33 @@ static int tomoyo_update_domain_keeper_e
}

/**
+ * tomoyo_cleanup_keep_domain - Clean up deleted "struct tomoyo_domain_keeper_entry".
+ */
+void tomoyo_cleanup_keep_domain(void)
+{
+ struct tomoyo_domain_keeper_entry *ptr;
+ struct tomoyo_domain_keeper_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_domain_keeper_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_domain_keeper_list,
+ entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_domain_keeper_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->domainname);
+ tomoyo_put_name(ptr->program);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
*
* @data: String to parse.
@@ -392,6 +425,7 @@ bool tomoyo_read_domain_keeper_policy(st

/***** READER SECTION START *****/
down_read(&tomoyo_domain_keeper_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2,
&tomoyo_domain_keeper_list) {
struct tomoyo_domain_keeper_entry *ptr;
@@ -399,7 +433,8 @@ bool tomoyo_read_domain_keeper_policy(st
const char *from = "";
const char *program = "";

- ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
+ ptr = list_entry(pos, struct tomoyo_domain_keeper_entry,
+ entry.list);
if (ptr->is_deleted)
continue;
no = ptr->is_not ? "no_" : "";
@@ -414,6 +449,7 @@ bool tomoyo_read_domain_keeper_policy(st
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_domain_keeper_list_lock);
/***** READER SECTION END *****/
return done;
@@ -438,7 +474,7 @@ static bool tomoyo_is_domain_keeper(cons

/***** READER SECTION START *****/
down_read(&tomoyo_domain_keeper_list_lock);
- list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
+ list_for_each_entry(ptr, &tomoyo_domain_keeper_list, entry.list) {
if (ptr->is_deleted)
continue;
if (!ptr->is_last_name) {
@@ -498,7 +534,7 @@ static int tomoyo_update_alias_entry(con
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_alias_list_lock);
- list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+ list_for_each_entry(ptr, &tomoyo_alias_list, entry.list) {
if (ptr->original_name != saved_original_name ||
ptr->aliased_name != saved_aliased_name)
continue;
@@ -511,7 +547,7 @@ static int tomoyo_update_alias_entry(con
saved_original_name = NULL;
new_entry->aliased_name = saved_aliased_name;
saved_aliased_name = NULL;
- list_add_tail(&new_entry->list, &tomoyo_alias_list);
+ list_add_tail(&new_entry->entry.list, &tomoyo_alias_list);
new_entry = NULL;
error = 0;
}
@@ -524,6 +560,32 @@ static int tomoyo_update_alias_entry(con
}

/**
+ * tomoyo_cleanup_alias - Clean up deleted "struct tomoyo_alias_entry".
+ */
+void tomoyo_cleanup_alias(void)
+{
+ struct tomoyo_alias_entry *ptr;
+ struct tomoyo_alias_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_alias_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_alias_list, entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_alias_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->original_name);
+ tomoyo_put_name(ptr->aliased_name);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -537,10 +599,11 @@ bool tomoyo_read_alias_policy(struct tom

/***** READER SECTION START *****/
down_read(&tomoyo_alias_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
struct tomoyo_alias_entry *ptr;

- ptr = list_entry(pos, struct tomoyo_alias_entry, list);
+ ptr = list_entry(pos, struct tomoyo_alias_entry, entry.list);
if (ptr->is_deleted)
continue;
done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
@@ -549,6 +612,7 @@ bool tomoyo_read_alias_policy(struct tom
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_alias_list_lock);
/***** READER SECTION END *****/
return done;
@@ -572,40 +636,6 @@ int tomoyo_write_alias_policy(char *data
return tomoyo_update_alias_entry(data, cp, is_delete);
}

-/* Domain create/delete handler. */
-
-/**
- * tomoyo_delete_domain - Delete a domain.
- *
- * @domainname: The name of domain.
- *
- * Returns 0.
- */
-int tomoyo_delete_domain(char *domainname)
-{
- struct tomoyo_domain_info *domain;
- struct tomoyo_path_info name;
-
- name.name = domainname;
- tomoyo_fill_path_info(&name);
- /***** WRITER SECTION START *****/
- down_write(&tomoyo_domain_list_lock);
- /* Is there an active domain? */
- list_for_each_entry(domain, &tomoyo_domain_list, list) {
- /* Never delete tomoyo_kernel_domain */
- if (domain == &tomoyo_kernel_domain)
- continue;
- if (domain->is_deleted ||
- tomoyo_pathcmp(domain->domainname, &name))
- continue;
- domain->is_deleted = true;
- break;
- }
- up_write(&tomoyo_domain_list_lock);
- /***** WRITER SECTION END *****/
- return 0;
-}
-
/**
* tomoyo_find_or_assign_new_domain - Create a domain.
*
@@ -619,79 +649,56 @@ struct tomoyo_domain_info *tomoyo_find_o
const u8 profile)
{
struct tomoyo_domain_info *new_domain = NULL;
- struct tomoyo_domain_info *domain;
- const struct tomoyo_path_info *saved_domainname;
+ struct tomoyo_domain_info *domain = NULL;
+ const struct tomoyo_path_info *saved_domainname = NULL;
+ bool found = false;

+ up_read(&tomoyo_domain_list_lock);
+ /***** READER SECTION END *****/
if (!tomoyo_is_correct_domain(domainname, __func__))
- return NULL;
+ goto out;
saved_domainname = tomoyo_get_name(domainname);
if (!saved_domainname)
- return NULL;
+ goto out;
new_domain = kmalloc(sizeof(*new_domain), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_domain_list_lock);
- domain = tomoyo_find_domain(domainname);
- if (domain)
- 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 ||
+ list_for_each_entry(domain, &tomoyo_domain_list, entry.list) {
+ 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;
+ found = true;
+ break;
}
- /* No memory reusable. Create using new memory. */
- if (tomoyo_memory_ok(new_domain)) {
+ if (!found && tomoyo_memory_ok(new_domain)) {
domain = new_domain;
new_domain = NULL;
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);
+ list_add_tail(&domain->entry.list, &tomoyo_domain_list);
+ found = true;
}
- out:
up_write(&tomoyo_domain_list_lock);
/***** WRITER SECTION END *****/
+ out:
tomoyo_put_name(saved_domainname);
kfree(new_domain);
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_domain_list_lock);
+ return found ? domain : NULL;
return domain;
}

/**
* 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
@@ -752,7 +759,7 @@ int tomoyo_find_next_domain(struct linux
/* Is this program allowed to be called via symbolic links? */
/***** READER SECTION START *****/
down_read(&tomoyo_alias_list_lock);
- list_for_each_entry(ptr, &tomoyo_alias_list, list) {
+ list_for_each_entry(ptr, &tomoyo_alias_list, entry.list) {
if (ptr->is_deleted ||
tomoyo_pathcmp(&r, ptr->original_name) ||
tomoyo_pathcmp(&s, ptr->aliased_name))
@@ -793,33 +800,33 @@ int tomoyo_find_next_domain(struct linux
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;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_list_lock);
+ if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
+ goto done;
domain = tomoyo_find_domain(new_domain_name);
+ if (!domain && !is_enforce)
+ domain = tomoyo_find_or_assign_new_domain(new_domain_name,
+ old_domain->profile);
+ done:
+ if (!domain) {
+ printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
+ new_domain_name);
+ if (is_enforce)
+ retval = -EPERM;
+ else
+ old_domain->domain_transition_failed = true;
+ }
+ if (!domain)
+ domain = old_domain;
+ BUG_ON(bprm->cred->security);
+ atomic_inc(&domain->entry.users);
+ bprm->cred->security = domain;
up_read(&tomoyo_domain_list_lock);
/***** READER SECTION END *****/
- if (domain)
- goto done;
- if (is_enforce)
- goto done;
- domain = tomoyo_find_or_assign_new_domain(new_domain_name,
- old_domain->profile);
- done:
- if (domain)
- goto out;
- printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
- new_domain_name);
- if (is_enforce)
- retval = -EPERM;
- else
- tomoyo_set_domain_flag(old_domain, false,
- TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
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
@@ -16,21 +16,21 @@

/* Structure for "allow_read" keyword. */
struct tomoyo_globally_readable_file_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
const struct tomoyo_path_info *filename;
bool is_deleted;
};

/* Structure for "file_pattern" keyword. */
struct tomoyo_pattern_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
const struct tomoyo_path_info *pattern;
bool is_deleted;
};

/* Structure for "deny_rewrite" keyword. */
struct tomoyo_no_rewrite_entry {
- struct list_head list;
+ struct tomoyo_entry entry;
const struct tomoyo_path_info *pattern;
bool is_deleted;
};
@@ -170,7 +170,7 @@ static int tomoyo_update_globally_readab
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_globally_readable_list_lock);
- list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+ list_for_each_entry(ptr, &tomoyo_globally_readable_list, entry.list) {
if (ptr->filename != saved_filename)
continue;
ptr->is_deleted = is_delete;
@@ -180,7 +180,8 @@ static int tomoyo_update_globally_readab
if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
new_entry->filename = saved_filename;
saved_filename = NULL;
- list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
+ list_add_tail(&new_entry->entry.list,
+ &tomoyo_globally_readable_list);
new_entry = NULL;
error = 0;
}
@@ -192,6 +193,32 @@ static int tomoyo_update_globally_readab
}

/**
+ * tomoyo_cleanup_allow_read - Clean up deleted "struct tomoyo_globally_readable_file_entry".
+ */
+void tomoyo_cleanup_allow_read(void)
+{
+ struct tomoyo_globally_readable_file_entry *ptr;
+ struct tomoyo_globally_readable_file_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_globally_readable_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_globally_readable_list,
+ entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_globally_readable_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->filename);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
*
* @filename: The filename to check.
@@ -205,7 +232,7 @@ static bool tomoyo_is_globally_readable_
bool found = false;
/***** READER SECTION START *****/
down_read(&tomoyo_globally_readable_list_lock);
- list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
+ list_for_each_entry(ptr, &tomoyo_globally_readable_list, entry.list) {
if (!ptr->is_deleted &&
tomoyo_path_matches_pattern(filename, ptr->filename)) {
found = true;
@@ -244,12 +271,13 @@ bool tomoyo_read_globally_readable_polic

/***** READER SECTION START *****/
down_read(&tomoyo_globally_readable_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2,
&tomoyo_globally_readable_list) {
struct tomoyo_globally_readable_file_entry *ptr;
ptr = list_entry(pos,
struct tomoyo_globally_readable_file_entry,
- list);
+ entry.list);
if (ptr->is_deleted)
continue;
done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
@@ -257,6 +285,7 @@ bool tomoyo_read_globally_readable_polic
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_globally_readable_list_lock);
/***** READER SECTION END *****/
return done;
@@ -291,7 +320,7 @@ static int tomoyo_update_file_pattern_en
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_pattern_list_lock);
- list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+ list_for_each_entry(ptr, &tomoyo_pattern_list, entry.list) {
if (saved_pattern != ptr->pattern)
continue;
ptr->is_deleted = is_delete;
@@ -301,7 +330,7 @@ static int tomoyo_update_file_pattern_en
if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
new_entry->pattern = saved_pattern;
saved_pattern = NULL;
- list_add_tail(&new_entry->list, &tomoyo_pattern_list);
+ list_add_tail(&new_entry->entry.list, &tomoyo_pattern_list);
new_entry = NULL;
error = 0;
}
@@ -313,38 +342,78 @@ static int tomoyo_update_file_pattern_en
}

/**
+ * tomoyo_cleanup_file_pattern - Clean up deleted "struct tomoyo_pattern_entry".
+ */
+void tomoyo_cleanup_file_pattern(void)
+{
+ struct tomoyo_pattern_entry *ptr;
+ struct tomoyo_pattern_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_pattern_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_pattern_list, entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_pattern_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->pattern);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_get_file_pattern - Get patterned pathname.
*
* @filename: The filename to find patterned pathname.
*
- * Returns pointer to pathname pattern if matched, @filename otherwise.
+ * Returns pointer to "struct tomoyo_pattern_entry" if matched, NULL otherwis \
+e.
+ *
+ * Caller must call tomoyo_put_file_pattern() if this function didn't return
+ * NULL.
*/
-static const struct tomoyo_path_info *
+static struct tomoyo_pattern_entry *
tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
{
struct tomoyo_pattern_entry *ptr;
- const struct tomoyo_path_info *pattern = NULL;
+ struct tomoyo_pattern_entry *pattern = NULL;

/***** READER SECTION START *****/
down_read(&tomoyo_pattern_list_lock);
- list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
+ list_for_each_entry(ptr, &tomoyo_pattern_list, entry.list) {
if (ptr->is_deleted)
continue;
if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
continue;
- pattern = ptr->pattern;
- if (tomoyo_strendswith(pattern->name, "/\\*")) {
+ pattern = ptr;
+ if (tomoyo_strendswith(ptr->pattern->name, "/\\*")) {
/* Do nothing. Try to find the better match. */
} else {
/* This would be the better match. Use this. */
break;
}
}
+ if (pattern)
+ atomic_inc(&pattern->entry.users);
+ up_read(&tomoyo_pattern_list_lock);
+ /***** READER SECTION END *****/
+ return pattern;
+}
+
+static void tomoyo_put_file_pattern(struct tomoyo_pattern_entry *name)
+{
+ if (!name)
+ return;
+ /***** READER SECTION START *****/
+ down_read(&tomoyo_pattern_list_lock);
+ atomic_dec(&name->entry.users);
up_read(&tomoyo_pattern_list_lock);
/***** READER SECTION END *****/
- if (pattern)
- filename = pattern;
- return filename;
}

/**
@@ -374,9 +443,10 @@ bool tomoyo_read_file_pattern(struct tom

/***** READER SECTION START *****/
down_read(&tomoyo_pattern_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
struct tomoyo_pattern_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
+ ptr = list_entry(pos, struct tomoyo_pattern_entry, entry.list);
if (ptr->is_deleted)
continue;
done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN
@@ -384,6 +454,7 @@ bool tomoyo_read_file_pattern(struct tom
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_pattern_list_lock);
/***** READER SECTION END *****/
return done;
@@ -418,7 +489,7 @@ static int tomoyo_update_no_rewrite_entr
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
/***** WRITER SECTION START *****/
down_write(&tomoyo_no_rewrite_list_lock);
- list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+ list_for_each_entry(ptr, &tomoyo_no_rewrite_list, entry.list) {
if (ptr->pattern != saved_pattern)
continue;
ptr->is_deleted = is_delete;
@@ -428,7 +499,7 @@ static int tomoyo_update_no_rewrite_entr
if (!is_delete && error && tomoyo_memory_ok(new_entry)) {
new_entry->pattern = saved_pattern;
saved_pattern = NULL;
- list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
+ list_add_tail(&new_entry->entry.list, &tomoyo_no_rewrite_list);
new_entry = NULL;
error = 0;
}
@@ -440,6 +511,32 @@ static int tomoyo_update_no_rewrite_entr
}

/**
+ * tomoyo_cleanup_no_rewrite - Clean up deleted "struct tomoyo_no_rewrite_entry".
+ */
+void tomoyo_cleanup_no_rewrite(void)
+{
+ struct tomoyo_no_rewrite_entry *ptr;
+ struct tomoyo_no_rewrite_entry *tmp;
+ LIST_HEAD(q);
+ /***** WRITER SECTION START *****/
+ down_write(&tomoyo_no_rewrite_list_lock);
+ list_for_each_entry_safe(ptr, tmp, &tomoyo_no_rewrite_list,
+ entry.list) {
+ if (!ptr->is_deleted || atomic_read(&ptr->entry.users))
+ continue;
+ list_del(&ptr->entry.list);
+ list_add(&ptr->entry.list, &q);
+ }
+ up_write(&tomoyo_no_rewrite_list_lock);
+ /***** WRITER SECTION END *****/
+ list_for_each_entry_safe(ptr, tmp, &q, entry.list) {
+ tomoyo_put_name(ptr->pattern);
+ list_del(&ptr->entry.list);
+ tomoyo_free_element(ptr);
+ }
+}
+
+/**
* tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
*
* @filename: Filename to check.
@@ -454,7 +551,7 @@ static bool tomoyo_is_no_rewrite_file(co

/***** READER SECTION START *****/
down_read(&tomoyo_no_rewrite_list_lock);
- list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
+ list_for_each_entry(ptr, &tomoyo_no_rewrite_list, entry.list) {
if (ptr->is_deleted)
continue;
if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
@@ -494,9 +591,11 @@ bool tomoyo_read_no_rewrite_policy(struc

/***** READER SECTION START *****/
down_read(&tomoyo_no_rewrite_list_lock);
+ tomoyo_put_ref(head->read_var2);
list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
struct tomoyo_no_rewrite_entry *ptr;
- ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
+ ptr = list_entry(pos, struct tomoyo_no_rewrite_entry,
+ entry.list);
if (ptr->is_deleted)
continue;
done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE
@@ -504,6 +603,7 @@ bool tomoyo_read_no_rewrite_policy(struc
if (!done)
break;
}
+ tomoyo_get_ref(head->read_var2);
up_read(&tomoyo_no_rewrite_list_lock);
/***** READER SECTION END *****/
return done;
@@ -573,7 +673,7 @@ static int tomoyo_check_single_path_acl2

/***** READER SECTION START *****/
down_read(&tomoyo_domain_acl_info_list_lock);
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
@@ -650,8 +750,7 @@ static int tomoyo_check_file_perm2(struc
if (!filename)
return 0;
error = tomoyo_check_file_acl(domain, filename, perm);
- if (error && perm == 4 &&
- (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
+ if (error && perm == 4 && !domain->ignore_global_allow_read
&& tomoyo_is_globally_readable_file(filename))
error = 0;
if (perm == 6)
@@ -673,11 +772,13 @@ static int tomoyo_check_file_perm2(struc
if (is_enforce)
return error;
if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
+ struct tomoyo_pattern_entry *p = NULL;
/* 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)
+ p = tomoyo_get_file_pattern(filename);
+ tomoyo_update_file_acl(p ? p->pattern->name : filename->name,
+ perm, domain, false);
+ tomoyo_put_file_pattern(p);
}
return 0;
}
@@ -763,7 +864,7 @@ static int tomoyo_update_single_path_acl
down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete)
goto delete;
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
@@ -791,13 +892,14 @@ static int tomoyo_update_single_path_acl
new_entry->perm |= rw_mask;
new_entry->filename = saved_filename;
saved_filename = NULL;
- list_add_tail(&new_entry->head.list, &domain->acl_info_list);
+ list_add_tail(&new_entry->head.entry.list,
+ &domain->acl_info_list);
new_entry = NULL;
error = 0;
}
goto out;
delete:
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
struct tomoyo_single_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
continue;
@@ -864,7 +966,7 @@ static int tomoyo_update_double_path_acl
down_write(&tomoyo_domain_acl_info_list_lock);
if (is_delete)
goto delete;
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
@@ -889,13 +991,14 @@ static int tomoyo_update_double_path_acl
saved_filename1 = NULL;
new_entry->filename2 = saved_filename2;
saved_filename2 = NULL;
- list_add_tail(&new_entry->head.list, &domain->acl_info_list);
+ list_add_tail(&new_entry->head.entry.list,
+ &domain->acl_info_list);
new_entry = NULL;
error = 0;
}
goto out;
delete:
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
@@ -962,7 +1065,7 @@ static int tomoyo_check_double_path_acl(
return 0;
/***** READER SECTION START *****/
down_read(&tomoyo_domain_acl_info_list_lock);
- list_for_each_entry(ptr, &domain->acl_info_list, list) {
+ list_for_each_entry(ptr, &domain->acl_info_list, entry.list) {
struct tomoyo_double_path_acl_record *acl;
if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
continue;
@@ -1013,8 +1116,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_pattern_entry *p
+ = tomoyo_get_file_pattern(filename);
+ tomoyo_update_single_path_acl(operation,
+ p ? p->pattern->name :
+ filename->name, domain, false);
+ tomoyo_put_file_pattern(p);
}
if (!is_enforce)
error = 0;
@@ -1260,10 +1367,18 @@ 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_pattern_entry *p1
+ = tomoyo_get_file_pattern(buf1);
+ struct tomoyo_pattern_entry *p2
+ = tomoyo_get_file_pattern(buf2);
+ tomoyo_update_double_path_acl(operation,
+ p1 ? p1->pattern->name :
+ buf1->name,
+ p2 ? p2->pattern->name :
+ buf2->name, domain,
false);
+ tomoyo_put_file_pattern(p1);
+ tomoyo_put_file_pattern(p2);
}
out:
tomoyo_free(buf1);
--- security-testing-2.6.git.orig/security/tomoyo/realpath.c
+++ security-testing-2.6.git/security/tomoyo/realpath.c
@@ -223,6 +223,17 @@ bool tomoyo_memory_ok(void *ptr)
return false;
}

+/**
+ * tomoyo_free_element - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ */
+void tomoyo_free_element(void *ptr)
+{
+ atomic_sub(ksize(ptr), &tomoyo_allocated_memory_for_elements);
+ kfree(ptr);
+}
+
/* Memory allocated for string data in bytes. */
static atomic_t tomoyo_allocated_memory_for_savename;
/* Quota for holding string data in bytes. */
@@ -238,16 +249,13 @@ 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;
};

-/*
- * The list for "struct tomoyo_name_entry".
- *
- * This list is updated only inside tomoyo_get_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_get_name - Allocate permanent memory for string data.
@@ -255,8 +263,6 @@ static struct list_head tomoyo_name_list
* @name: The string to store into the permernent memory.
*
* 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_get_name(const char *name)
{
@@ -278,11 +284,12 @@ const struct tomoyo_path_info *tomoyo_ge
entry = kmalloc(sizeof(*entry) + len, GFP_KERNEL);
allocated_len = entry ? ksize(entry) : 0;
/***** 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))
continue;
+ atomic_inc(&ptr->users);
error = 0;
break;
}
@@ -297,12 +304,13 @@ const struct tomoyo_path_info *tomoyo_ge
ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
memmove((char *) ptr->entry.name, name, len);
tomoyo_fill_path_info(&ptr->entry);
+ atomic_set(&ptr->users, 1);
list_add_tail(&ptr->list,
&tomoyo_name_list[hash % TOMOYO_MAX_HASH]);
entry = NULL;
error = 0;
}
- mutex_unlock(&lock);
+ mutex_unlock(&tomoyo_name_list_lock);
/***** EXCLUSIVE SECTION END *****/
kfree(entry);
if (!error)
@@ -314,6 +322,33 @@ const struct tomoyo_path_info *tomoyo_ge
}

/**
+ * tomoyo_put_name - Delete shared memory for string data.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info".
+ */
+void tomoyo_put_name(const struct tomoyo_path_info *name)
+{
+ struct tomoyo_name_entry *ptr;
+ bool can_delete = false;
+
+ if (!name)
+ return;
+ ptr = container_of(name, struct tomoyo_name_entry, entry);
+ /***** EXCLUSIVE SECTION START *****/
+ mutex_lock(&tomoyo_name_list_lock);
+ if (atomic_dec_and_test(&ptr->users)) {
+ list_del(&ptr->list);
+ can_delete = true;
+ }
+ mutex_unlock(&tomoyo_name_list_lock);
+ /***** EXCLUSIVE SECTION END *****/
+ if (can_delete) {
+ atomic_sub(ksize(ptr), &tomoyo_allocated_memory_for_savename);
+ kfree(ptr);
+ }
+}
+
+/**
* tomoyo_realpath_init - Initialize realpath related code.
*/
void __init tomoyo_realpath_init(void)
@@ -325,7 +360,7 @@ void __init tomoyo_realpath_init(void)
INIT_LIST_HEAD(&tomoyo_name_list[i]);
INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
- list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+ list_add_tail(&tomoyo_kernel_domain.entry.list, &tomoyo_domain_list);
/***** READER SECTION START *****/
down_read(&tomoyo_domain_list_lock);
if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
--- security-testing-2.6.git.orig/security/tomoyo/realpath.h
+++ security-testing-2.6.git/security/tomoyo/realpath.h
@@ -44,10 +44,7 @@ bool tomoyo_memory_ok(void *ptr);
* The RAM is shared, so NEVER try to modify or kfree() the returned name.
*/
const struct tomoyo_path_info *tomoyo_get_name(const char *name);
-static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
-{
- /* It's a dummy so far. */
-}
+void tomoyo_put_name(const struct tomoyo_path_info *name);

/* Allocate memory for temporary use (e.g. permission checks). */
void *tomoyo_alloc(const size_t size);
@@ -55,6 +52,8 @@ void *tomoyo_alloc(const size_t size);
/* Free memory allocated by tomoyo_alloc(). */
void tomoyo_free(const void *p);

+void tomoyo_free_element(void *p);
+
/* Check for memory usage. */
int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);

--- security-testing-2.6.git.orig/security/tomoyo/tomoyo.c
+++ security-testing-2.6.git/security/tomoyo/tomoyo.c
@@ -22,9 +22,19 @@ static int tomoyo_cred_prepare(struct cr
* we don't need to duplicate.
*/
new->security = old->security;
+ if (new->security)
+ atomic_inc(&((struct tomoyo_domain_info *)
+ new->security)->entry.users);
return 0;
}

+static void tomoyo_cred_free(struct cred *cred)
+{
+ struct tomoyo_domain_info *domain = cred->security;
+ if (domain)
+ atomic_dec(&domain->entry.users);
+}
+
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
{
int rc;
@@ -49,7 +59,11 @@ 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;
+ if (bprm->cred->security) {
+ atomic_dec(&((struct tomoyo_domain_info *)
+ bprm->cred->security)->entry.users);
+ bprm->cred->security = NULL;
+ }
return 0;
}

@@ -61,14 +75,8 @@ static int tomoyo_bprm_check_security(st
* 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).
@@ -265,6 +273,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
@@ -293,6 +302,7 @@ static int __init tomoyo_init(void)
panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain;
+ atomic_inc(&tomoyo_kernel_domain.entry.users);
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. */

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