diff options
| author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-02-10 19:43:54 -0500 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2010-02-14 17:00:24 -0500 |
| commit | 847b173ea3d6f50936823d07f2245059bf44713b (patch) | |
| tree | b53c6d0536af73a078bcff0375f9f4d837f79bba | |
| parent | ec8e6a4e062e2edebef91e930c20572c9f4c0dda (diff) | |
TOMOYO: Add garbage collector.
This patch adds garbage collector support to TOMOYO.
Elements are protected by "struct srcu_struct tomoyo_ss".
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
| -rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
| -rw-r--r-- | security/tomoyo/common.c | 5 | ||||
| -rw-r--r-- | security/tomoyo/common.h | 15 | ||||
| -rw-r--r-- | security/tomoyo/domain.c | 6 | ||||
| -rw-r--r-- | security/tomoyo/file.c | 6 | ||||
| -rw-r--r-- | security/tomoyo/gc.c | 370 | ||||
| -rw-r--r-- | security/tomoyo/realpath.c | 86 |
7 files changed, 436 insertions, 54 deletions
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 10ccd686b290..60a9e2002da1 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
| @@ -1 +1 @@ | |||
| obj-y = common.o realpath.o tomoyo.o domain.o file.o | obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 634f7449e8ba..3a36b56a2f5c 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
| @@ -1067,7 +1067,7 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
| 1067 | * | 1067 | * |
| 1068 | * # cat /sys/kernel/security/tomoyo/manager | 1068 | * # cat /sys/kernel/security/tomoyo/manager |
| 1069 | */ | 1069 | */ |
| 1070 | static LIST_HEAD(tomoyo_policy_manager_list); | 1070 | LIST_HEAD(tomoyo_policy_manager_list); |
| 1071 | 1071 | ||
| 1072 | /** | 1072 | /** |
| 1073 | * tomoyo_update_manager_entry - Add a manager entry. | 1073 | * tomoyo_update_manager_entry - Add a manager entry. |
| @@ -2109,6 +2109,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
| 2109 | static int tomoyo_close_control(struct file *file) | 2109 | static int tomoyo_close_control(struct file *file) |
| 2110 | { | 2110 | { |
| 2111 | struct tomoyo_io_buffer *head = file->private_data; | 2111 | struct tomoyo_io_buffer *head = file->private_data; |
| 2112 | const bool is_write = !!head->write_buf; | ||
| 2112 | 2113 | ||
| 2113 | tomoyo_read_unlock(head->reader_idx); | 2114 | tomoyo_read_unlock(head->reader_idx); |
| 2114 | /* Release memory used for policy I/O. */ | 2115 | /* Release memory used for policy I/O. */ |
| @@ -2119,6 +2120,8 @@ static int tomoyo_close_control(struct file *file) | |||
| 2119 | kfree(head); | 2120 | kfree(head); |
| 2120 | head = NULL; | 2121 | head = NULL; |
| 2121 | file->private_data = NULL; | 2122 | file->private_data = NULL; |
| 2123 | if (is_write) | ||
| 2124 | tomoyo_run_gc(); | ||
| 2122 | return 0; | 2125 | return 0; |
| 2123 | } | 2126 | } |
| 2124 | 2127 | ||
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 521b4b5addaf..1c8c97a4c069 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
| @@ -638,6 +638,11 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | |||
| 638 | struct file *filp); | 638 | struct file *filp); |
| 639 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | 639 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
| 640 | 640 | ||
| 641 | /* Run garbage collector. */ | ||
| 642 | void tomoyo_run_gc(void); | ||
| 643 | |||
| 644 | void tomoyo_memory_free(void *ptr); | ||
| 645 | |||
| 641 | /********** External variable definitions. **********/ | 646 | /********** External variable definitions. **********/ |
| 642 | 647 | ||
| 643 | /* Lock for GC. */ | 648 | /* Lock for GC. */ |
| @@ -646,6 +651,16 @@ extern struct srcu_struct tomoyo_ss; | |||
| 646 | /* The list for "struct tomoyo_domain_info". */ | 651 | /* The list for "struct tomoyo_domain_info". */ |
| 647 | extern struct list_head tomoyo_domain_list; | 652 | extern struct list_head tomoyo_domain_list; |
| 648 | 653 | ||
| 654 | extern struct list_head tomoyo_domain_initializer_list; | ||
| 655 | extern struct list_head tomoyo_domain_keeper_list; | ||
| 656 | extern struct list_head tomoyo_alias_list; | ||
| 657 | extern struct list_head tomoyo_globally_readable_list; | ||
| 658 | extern struct list_head tomoyo_pattern_list; | ||
| 659 | extern struct list_head tomoyo_no_rewrite_list; | ||
| 660 | extern struct list_head tomoyo_policy_manager_list; | ||
| 661 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | ||
| 662 | extern struct mutex tomoyo_name_list_lock; | ||
| 663 | |||
| 649 | /* Lock for protecting policy. */ | 664 | /* Lock for protecting policy. */ |
| 650 | extern struct mutex tomoyo_policy_lock; | 665 | extern struct mutex tomoyo_policy_lock; |
| 651 | 666 | ||
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 6f74b30d6bb1..74cd0f52e3a8 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
| @@ -110,7 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
| 110 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | 110 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain |
| 111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | 111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. |
| 112 | */ | 112 | */ |
| 113 | static LIST_HEAD(tomoyo_domain_initializer_list); | 113 | LIST_HEAD(tomoyo_domain_initializer_list); |
| 114 | 114 | ||
| 115 | /** | 115 | /** |
| 116 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 116 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. |
| @@ -330,7 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
| 330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | 330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless |
| 331 | * explicitly specified by "initialize_domain". | 331 | * explicitly specified by "initialize_domain". |
| 332 | */ | 332 | */ |
| 333 | static LIST_HEAD(tomoyo_domain_keeper_list); | 333 | LIST_HEAD(tomoyo_domain_keeper_list); |
| 334 | 334 | ||
| 335 | /** | 335 | /** |
| 336 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | 336 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. |
| @@ -533,7 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
| 533 | * /bin/busybox and domainname which the current process will belong to after | 533 | * /bin/busybox and domainname which the current process will belong to after |
| 534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | 534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . |
| 535 | */ | 535 | */ |
| 536 | static LIST_HEAD(tomoyo_alias_list); | 536 | LIST_HEAD(tomoyo_alias_list); |
| 537 | 537 | ||
| 538 | /** | 538 | /** |
| 539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. | 539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index c69dd39e6042..10ee7cece080 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
| @@ -148,7 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
| 148 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | 148 | * given "allow_read /lib/libc-2.5.so" to the domain which current process |
| 149 | * belongs to. | 149 | * belongs to. |
| 150 | */ | 150 | */ |
| 151 | static LIST_HEAD(tomoyo_globally_readable_list); | 151 | LIST_HEAD(tomoyo_globally_readable_list); |
| 152 | 152 | ||
| 153 | /** | 153 | /** |
| 154 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. | 154 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. |
| @@ -295,7 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
| 295 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | 295 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid |
| 296 | * current process from accessing other process's information. | 296 | * current process from accessing other process's information. |
| 297 | */ | 297 | */ |
| 298 | static LIST_HEAD(tomoyo_pattern_list); | 298 | LIST_HEAD(tomoyo_pattern_list); |
| 299 | 299 | ||
| 300 | /** | 300 | /** |
| 301 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. | 301 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. |
| @@ -448,7 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
| 448 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | 448 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't |
| 449 | * need to worry whether the file is already unlink()ed or not. | 449 | * need to worry whether the file is already unlink()ed or not. |
| 450 | */ | 450 | */ |
| 451 | static LIST_HEAD(tomoyo_no_rewrite_list); | 451 | LIST_HEAD(tomoyo_no_rewrite_list); |
| 452 | 452 | ||
| 453 | /** | 453 | /** |
| 454 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. | 454 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c new file mode 100644 index 000000000000..ee15da39387d --- /dev/null +++ b/security/tomoyo/gc.c | |||
| @@ -0,0 +1,370 @@ | |||
| 1 | /* | ||
| 2 | * security/tomoyo/gc.c | ||
| 3 | * | ||
| 4 | * Implementation of the Domain-Based Mandatory Access Control. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include "common.h" | ||
| 11 | #include <linux/kthread.h> | ||
| 12 | |||
| 13 | enum tomoyo_gc_id { | ||
| 14 | TOMOYO_ID_DOMAIN_INITIALIZER, | ||
| 15 | TOMOYO_ID_DOMAIN_KEEPER, | ||
| 16 | TOMOYO_ID_ALIAS, | ||
| 17 | TOMOYO_ID_GLOBALLY_READABLE, | ||
| 18 | TOMOYO_ID_PATTERN, | ||
| 19 | TOMOYO_ID_NO_REWRITE, | ||
| 20 | TOMOYO_ID_MANAGER, | ||
| 21 | TOMOYO_ID_NAME, | ||
| 22 | TOMOYO_ID_ACL, | ||
| 23 | TOMOYO_ID_DOMAIN | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct tomoyo_gc_entry { | ||
| 27 | struct list_head list; | ||
| 28 | int type; | ||
| 29 | void *element; | ||
| 30 | }; | ||
| 31 | static LIST_HEAD(tomoyo_gc_queue); | ||
| 32 | static DEFINE_MUTEX(tomoyo_gc_mutex); | ||
| 33 | |||
| 34 | /* Caller holds tomoyo_policy_lock mutex. */ | ||
| 35 | static bool tomoyo_add_to_gc(const int type, void *element) | ||
| 36 | { | ||
| 37 | struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
| 38 | if (!entry) | ||
| 39 | return false; | ||
| 40 | entry->type = type; | ||
| 41 | entry->element = element; | ||
| 42 | list_add(&entry->list, &tomoyo_gc_queue); | ||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 46 | static void tomoyo_del_allow_read | ||
| 47 | (struct tomoyo_globally_readable_file_entry *ptr) | ||
| 48 | { | ||
| 49 | tomoyo_put_name(ptr->filename); | ||
| 50 | } | ||
| 51 | |||
| 52 | static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) | ||
| 53 | { | ||
| 54 | tomoyo_put_name(ptr->pattern); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) | ||
| 58 | { | ||
| 59 | tomoyo_put_name(ptr->pattern); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void tomoyo_del_domain_initializer | ||
| 63 | (struct tomoyo_domain_initializer_entry *ptr) | ||
| 64 | { | ||
| 65 | tomoyo_put_name(ptr->domainname); | ||
| 66 | tomoyo_put_name(ptr->program); | ||
| 67 | } | ||
| 68 | |||
| 69 | static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) | ||
| 70 | { | ||
| 71 | tomoyo_put_name(ptr->domainname); | ||
| 72 | tomoyo_put_name(ptr->program); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) | ||
| 76 | { | ||
| 77 | tomoyo_put_name(ptr->original_name); | ||
| 78 | tomoyo_put_name(ptr->aliased_name); | ||
| 79 | } | ||
| 80 | |||
| 81 | static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) | ||
| 82 | { | ||
| 83 | tomoyo_put_name(ptr->manager); | ||
| 84 | } | ||
| 85 | |||
| 86 | static void tomoyo_del_acl(struct tomoyo_acl_info *acl) | ||
| 87 | { | ||
| 88 | switch (acl->type) { | ||
| 89 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | ||
| 90 | { | ||
| 91 | struct tomoyo_single_path_acl_record *entry | ||
| 92 | = container_of(acl, typeof(*entry), head); | ||
| 93 | tomoyo_put_name(entry->filename); | ||
| 94 | } | ||
| 95 | break; | ||
| 96 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | ||
| 97 | { | ||
| 98 | struct tomoyo_double_path_acl_record *entry | ||
| 99 | = container_of(acl, typeof(*entry), head); | ||
| 100 | tomoyo_put_name(entry->filename1); | ||
| 101 | tomoyo_put_name(entry->filename2); | ||
| 102 | } | ||
| 103 | break; | ||
| 104 | default: | ||
| 105 | printk(KERN_WARNING "Unknown type\n"); | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) | ||
| 111 | { | ||
| 112 | struct tomoyo_acl_info *acl; | ||
| 113 | struct tomoyo_acl_info *tmp; | ||
| 114 | /* | ||
| 115 | * Since we don't protect whole execve() operation using SRCU, | ||
| 116 | * we need to recheck domain->users at this point. | ||
| 117 | * | ||
| 118 | * (1) Reader starts SRCU section upon execve(). | ||
| 119 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
| 120 | * (3) Writer marks this domain as deleted. | ||
| 121 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
| 122 | * because this domain is marked as deleted and used by nobody. | ||
| 123 | * (5) Reader saves reference to this domain into | ||
| 124 | * "struct linux_binprm"->cred->security . | ||
| 125 | * (6) Reader finishes SRCU section, although execve() operation has | ||
| 126 | * not finished yet. | ||
| 127 | * (7) Garbage collector waits for SRCU synchronization. | ||
| 128 | * (8) Garbage collector kfree() this domain because this domain is | ||
| 129 | * used by nobody. | ||
| 130 | * (9) Reader finishes execve() operation and restores this domain from | ||
| 131 | * "struct linux_binprm"->cred->security. | ||
| 132 | * | ||
| 133 | * By updating domain->users at (5), we can solve this race problem | ||
| 134 | * by rechecking domain->users at (8). | ||
| 135 | */ | ||
| 136 | if (atomic_read(&domain->users)) | ||
| 137 | return false; | ||
| 138 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | ||
| 139 | tomoyo_del_acl(acl); | ||
| 140 | tomoyo_memory_free(acl); | ||
| 141 | } | ||
| 142 | tomoyo_put_name(domain->domainname); | ||
| 143 | return true; | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) | ||
| 148 | { | ||
| 149 | } | ||
| 150 | |||
| 151 | static void tomoyo_collect_entry(void) | ||
| 152 | { | ||
| 153 | mutex_lock(&tomoyo_policy_lock); | ||
| 154 | { | ||
| 155 | struct tomoyo_globally_readable_file_entry *ptr; | ||
| 156 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, | ||
| 157 | list) { | ||
| 158 | if (!ptr->is_deleted) | ||
| 159 | continue; | ||
| 160 | if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) | ||
| 161 | list_del_rcu(&ptr->list); | ||
| 162 | else | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | { | ||
| 167 | struct tomoyo_pattern_entry *ptr; | ||
| 168 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
| 169 | if (!ptr->is_deleted) | ||
| 170 | continue; | ||
| 171 | if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) | ||
| 172 | list_del_rcu(&ptr->list); | ||
| 173 | else | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | { | ||
| 178 | struct tomoyo_no_rewrite_entry *ptr; | ||
| 179 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
| 180 | if (!ptr->is_deleted) | ||
| 181 | continue; | ||
| 182 | if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) | ||
| 183 | list_del_rcu(&ptr->list); | ||
| 184 | else | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | { | ||
| 189 | struct tomoyo_domain_initializer_entry *ptr; | ||
| 190 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, | ||
| 191 | list) { | ||
| 192 | if (!ptr->is_deleted) | ||
| 193 | continue; | ||
| 194 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) | ||
| 195 | list_del_rcu(&ptr->list); | ||
| 196 | else | ||
| 197 | break; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | { | ||
| 201 | struct tomoyo_domain_keeper_entry *ptr; | ||
| 202 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
| 203 | if (!ptr->is_deleted) | ||
| 204 | continue; | ||
| 205 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) | ||
| 206 | list_del_rcu(&ptr->list); | ||
| 207 | else | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | { | ||
| 212 | struct tomoyo_alias_entry *ptr; | ||
| 213 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
| 214 | if (!ptr->is_deleted) | ||
| 215 | continue; | ||
| 216 | if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) | ||
| 217 | list_del_rcu(&ptr->list); | ||
| 218 | else | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | { | ||
| 223 | struct tomoyo_policy_manager_entry *ptr; | ||
| 224 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, | ||
| 225 | list) { | ||
| 226 | if (!ptr->is_deleted) | ||
| 227 | continue; | ||
| 228 | if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) | ||
| 229 | list_del_rcu(&ptr->list); | ||
| 230 | else | ||
| 231 | break; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | { | ||
| 235 | struct tomoyo_domain_info *domain; | ||
| 236 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
| 237 | struct tomoyo_acl_info *acl; | ||
| 238 | list_for_each_entry_rcu(acl, &domain->acl_info_list, | ||
| 239 | list) { | ||
| 240 | switch (acl->type) { | ||
| 241 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | ||
| 242 | if (container_of(acl, | ||
| 243 | struct tomoyo_single_path_acl_record, | ||
| 244 | head)->perm || | ||
| 245 | container_of(acl, | ||
| 246 | struct tomoyo_single_path_acl_record, | ||
| 247 | head)->perm_high) | ||
| 248 | continue; | ||
| 249 | break; | ||
| 250 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | ||
| 251 | if (container_of(acl, | ||
| 252 | struct tomoyo_double_path_acl_record, | ||
| 253 | head)->perm) | ||
| 254 | continue; | ||
| 255 | break; | ||
| 256 | default: | ||
| 257 | continue; | ||
| 258 | } | ||
| 259 | if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) | ||
| 260 | list_del_rcu(&acl->list); | ||
| 261 | else | ||
| 262 | break; | ||
| 263 | } | ||
| 264 | if (!domain->is_deleted || atomic_read(&domain->users)) | ||
| 265 | continue; | ||
| 266 | /* | ||
| 267 | * Nobody is referring this domain. But somebody may | ||
| 268 | * refer this domain after successful execve(). | ||
| 269 | * We recheck domain->users after SRCU synchronization. | ||
| 270 | */ | ||
| 271 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) | ||
| 272 | list_del_rcu(&domain->list); | ||
| 273 | else | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | mutex_unlock(&tomoyo_policy_lock); | ||
| 278 | mutex_lock(&tomoyo_name_list_lock); | ||
| 279 | { | ||
| 280 | int i; | ||
| 281 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | ||
| 282 | struct tomoyo_name_entry *ptr; | ||
| 283 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], | ||
| 284 | list) { | ||
| 285 | if (atomic_read(&ptr->users)) | ||
| 286 | continue; | ||
| 287 | if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) | ||
| 288 | list_del_rcu(&ptr->list); | ||
| 289 | else { | ||
| 290 | i = TOMOYO_MAX_HASH; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | mutex_unlock(&tomoyo_name_list_lock); | ||
| 297 | } | ||
| 298 | |||
| 299 | static void tomoyo_kfree_entry(void) | ||
| 300 | { | ||
| 301 | struct tomoyo_gc_entry *p; | ||
| 302 | struct tomoyo_gc_entry *tmp; | ||
| 303 | |||
| 304 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { | ||
| 305 | switch (p->type) { | ||
| 306 | case TOMOYO_ID_DOMAIN_INITIALIZER: | ||
| 307 | tomoyo_del_domain_initializer(p->element); | ||
| 308 | break; | ||
| 309 | case TOMOYO_ID_DOMAIN_KEEPER: | ||
| 310 | tomoyo_del_domain_keeper(p->element); | ||
| 311 | break; | ||
| 312 | case TOMOYO_ID_ALIAS: | ||
| 313 | tomoyo_del_alias(p->element); | ||
| 314 | break; | ||
| 315 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
| 316 | tomoyo_del_allow_read(p->element); | ||
| 317 | break; | ||
| 318 | case TOMOYO_ID_PATTERN: | ||
| 319 | tomoyo_del_file_pattern(p->element); | ||
| 320 | break; | ||
| 321 | case TOMOYO_ID_NO_REWRITE: | ||
| 322 | tomoyo_del_no_rewrite(p->element); | ||
| 323 | break; | ||
| 324 | case TOMOYO_ID_MANAGER: | ||
| 325 | tomoyo_del_manager(p->element); | ||
| 326 | break; | ||
| 327 | case TOMOYO_ID_NAME: | ||
| 328 | tomoyo_del_name(p->element); | ||
| 329 | break; | ||
| 330 | case TOMOYO_ID_ACL: | ||
| 331 | tomoyo_del_acl(p->element); | ||
| 332 | break; | ||
| 333 | case TOMOYO_ID_DOMAIN: | ||
| 334 | if (!tomoyo_del_domain(p->element)) | ||
| 335 | continue; | ||
| 336 | break; | ||
| 337 | default: | ||
| 338 | printk(KERN_WARNING "Unknown type\n"); | ||
| 339 | break; | ||
| 340 | } | ||
| 341 | tomoyo_memory_free(p->element); | ||
| 342 | list_del(&p->list); | ||
| 343 | kfree(p); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | static int tomoyo_gc_thread(void *unused) | ||
| 348 | { | ||
| 349 | daemonize("GC for TOMOYO"); | ||
| 350 | if (mutex_trylock(&tomoyo_gc_mutex)) { | ||
| 351 | int i; | ||
| 352 | for (i = 0; i < 10; i++) { | ||
| 353 | tomoyo_collect_entry(); | ||
| 354 | if (list_empty(&tomoyo_gc_queue)) | ||
| 355 | break; | ||
| 356 | synchronize_srcu(&tomoyo_ss); | ||
| 357 | tomoyo_kfree_entry(); | ||
| 358 | } | ||
| 359 | mutex_unlock(&tomoyo_gc_mutex); | ||
| 360 | } | ||
| 361 | do_exit(0); | ||
| 362 | } | ||
| 363 | |||
| 364 | void tomoyo_run_gc(void) | ||
| 365 | { | ||
| 366 | struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, | ||
| 367 | "GC for TOMOYO"); | ||
| 368 | if (!IS_ERR(task)) | ||
| 369 | wake_up_process(task); | ||
| 370 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 9557168b3767..c00df45c7ede 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
| @@ -205,9 +205,9 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | /* Memory allocated for non-string data. */ | 207 | /* Memory allocated for non-string data. */ |
| 208 | static unsigned int tomoyo_allocated_memory_for_elements; | 208 | static atomic_t tomoyo_policy_memory_size; |
| 209 | /* Quota for holding non-string data. */ | 209 | /* Quota for holding policy. */ |
| 210 | static unsigned int tomoyo_quota_for_elements; | 210 | static unsigned int tomoyo_quota_for_policy; |
| 211 | 211 | ||
| 212 | /** | 212 | /** |
| 213 | * tomoyo_memory_ok - Check memory quota. | 213 | * tomoyo_memory_ok - Check memory quota. |
| @@ -222,26 +222,30 @@ static unsigned int tomoyo_quota_for_elements; | |||
| 222 | bool tomoyo_memory_ok(void *ptr) | 222 | bool tomoyo_memory_ok(void *ptr) |
| 223 | { | 223 | { |
| 224 | int allocated_len = ptr ? ksize(ptr) : 0; | 224 | int allocated_len = ptr ? ksize(ptr) : 0; |
| 225 | bool result = false; | 225 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
| 226 | if (!ptr || (tomoyo_quota_for_elements && | 226 | if (ptr && (!tomoyo_quota_for_policy || |
| 227 | tomoyo_allocated_memory_for_elements | 227 | atomic_read(&tomoyo_policy_memory_size) |
| 228 | + allocated_len > tomoyo_quota_for_elements)) { | 228 | <= tomoyo_quota_for_policy)) { |
| 229 | printk(KERN_WARNING "ERROR: Out of memory " | ||
| 230 | "for tomoyo_alloc_element().\n"); | ||
| 231 | if (!tomoyo_policy_loaded) | ||
| 232 | panic("MAC Initialization failed.\n"); | ||
| 233 | } else { | ||
| 234 | result = true; | ||
| 235 | tomoyo_allocated_memory_for_elements += allocated_len; | ||
| 236 | memset(ptr, 0, allocated_len); | 229 | memset(ptr, 0, allocated_len); |
| 230 | return true; | ||
| 237 | } | 231 | } |
| 238 | return result; | 232 | printk(KERN_WARNING "ERROR: Out of memory " |
| 233 | "for tomoyo_alloc_element().\n"); | ||
| 234 | if (!tomoyo_policy_loaded) | ||
| 235 | panic("MAC Initialization failed.\n"); | ||
| 236 | return false; | ||
| 239 | } | 237 | } |
| 240 | 238 | ||
| 241 | /* Memory allocated for string data in bytes. */ | 239 | /** |
| 242 | static unsigned int tomoyo_allocated_memory_for_savename; | 240 | * tomoyo_memory_free - Free memory for elements. |
| 243 | /* Quota for holding string data in bytes. */ | 241 | * |
| 244 | static unsigned int tomoyo_quota_for_savename; | 242 | * @ptr: Pointer to allocated memory. |
| 243 | */ | ||
| 244 | void tomoyo_memory_free(void *ptr) | ||
| 245 | { | ||
| 246 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); | ||
| 247 | kfree(ptr); | ||
| 248 | } | ||
| 245 | 249 | ||
| 246 | /* | 250 | /* |
| 247 | * tomoyo_name_list is used for holding string data used by TOMOYO. | 251 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
| @@ -249,7 +253,9 @@ static unsigned int tomoyo_quota_for_savename; | |||
| 249 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | 253 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
| 250 | * "const struct tomoyo_path_info *". | 254 | * "const struct tomoyo_path_info *". |
| 251 | */ | 255 | */ |
| 252 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 256 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
| 257 | /* Lock for protecting tomoyo_name_list . */ | ||
| 258 | DEFINE_MUTEX(tomoyo_name_list_lock); | ||
| 253 | 259 | ||
| 254 | /** | 260 | /** |
| 255 | * tomoyo_get_name - Allocate permanent memory for string data. | 261 | * tomoyo_get_name - Allocate permanent memory for string data. |
| @@ -260,7 +266,6 @@ static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | |||
| 260 | */ | 266 | */ |
| 261 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) | 267 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
| 262 | { | 268 | { |
| 263 | static DEFINE_MUTEX(lock); | ||
| 264 | struct tomoyo_name_entry *ptr; | 269 | struct tomoyo_name_entry *ptr; |
| 265 | unsigned int hash; | 270 | unsigned int hash; |
| 266 | int len; | 271 | int len; |
| @@ -272,7 +277,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
| 272 | len = strlen(name) + 1; | 277 | len = strlen(name) + 1; |
| 273 | hash = full_name_hash((const unsigned char *) name, len - 1); | 278 | hash = full_name_hash((const unsigned char *) name, len - 1); |
| 274 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 279 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
| 275 | mutex_lock(&lock); | 280 | mutex_lock(&tomoyo_name_list_lock); |
| 276 | list_for_each_entry(ptr, head, list) { | 281 | list_for_each_entry(ptr, head, list) { |
| 277 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 282 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
| 278 | continue; | 283 | continue; |
| @@ -281,9 +286,9 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
| 281 | } | 286 | } |
| 282 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); | 287 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); |
| 283 | allocated_len = ptr ? ksize(ptr) : 0; | 288 | allocated_len = ptr ? ksize(ptr) : 0; |
| 284 | if (!ptr || (tomoyo_quota_for_savename && | 289 | if (!ptr || (tomoyo_quota_for_policy && |
| 285 | tomoyo_allocated_memory_for_savename + allocated_len | 290 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
| 286 | > tomoyo_quota_for_savename)) { | 291 | > tomoyo_quota_for_policy)) { |
| 287 | kfree(ptr); | 292 | kfree(ptr); |
| 288 | printk(KERN_WARNING "ERROR: Out of memory " | 293 | printk(KERN_WARNING "ERROR: Out of memory " |
| 289 | "for tomoyo_get_name().\n"); | 294 | "for tomoyo_get_name().\n"); |
| @@ -292,14 +297,14 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
| 292 | ptr = NULL; | 297 | ptr = NULL; |
| 293 | goto out; | 298 | goto out; |
| 294 | } | 299 | } |
| 295 | tomoyo_allocated_memory_for_savename += allocated_len; | 300 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
| 296 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); | 301 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
| 297 | memmove((char *) ptr->entry.name, name, len); | 302 | memmove((char *) ptr->entry.name, name, len); |
| 298 | atomic_set(&ptr->users, 1); | 303 | atomic_set(&ptr->users, 1); |
| 299 | tomoyo_fill_path_info(&ptr->entry); | 304 | tomoyo_fill_path_info(&ptr->entry); |
| 300 | list_add_tail(&ptr->list, head); | 305 | list_add_tail(&ptr->list, head); |
| 301 | out: | 306 | out: |
| 302 | mutex_unlock(&lock); | 307 | mutex_unlock(&tomoyo_name_list_lock); |
| 303 | return ptr ? &ptr->entry : NULL; | 308 | return ptr ? &ptr->entry : NULL; |
| 304 | } | 309 | } |
| 305 | 310 | ||
| @@ -334,28 +339,19 @@ void __init tomoyo_realpath_init(void) | |||
| 334 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | 339 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
| 335 | { | 340 | { |
| 336 | if (!head->read_eof) { | 341 | if (!head->read_eof) { |
| 337 | const unsigned int shared | 342 | const unsigned int policy |
| 338 | = tomoyo_allocated_memory_for_savename; | 343 | = atomic_read(&tomoyo_policy_memory_size); |
| 339 | const unsigned int private | ||
| 340 | = tomoyo_allocated_memory_for_elements; | ||
| 341 | char buffer[64]; | 344 | char buffer[64]; |
| 342 | 345 | ||
| 343 | memset(buffer, 0, sizeof(buffer)); | 346 | memset(buffer, 0, sizeof(buffer)); |
| 344 | if (tomoyo_quota_for_savename) | 347 | if (tomoyo_quota_for_policy) |
| 345 | snprintf(buffer, sizeof(buffer) - 1, | ||
| 346 | " (Quota: %10u)", | ||
| 347 | tomoyo_quota_for_savename); | ||
| 348 | else | ||
| 349 | buffer[0] = '\0'; | ||
| 350 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); | ||
| 351 | if (tomoyo_quota_for_elements) | ||
| 352 | snprintf(buffer, sizeof(buffer) - 1, | 348 | snprintf(buffer, sizeof(buffer) - 1, |
| 353 | " (Quota: %10u)", | 349 | " (Quota: %10u)", |
| 354 | tomoyo_quota_for_elements); | 350 | tomoyo_quota_for_policy); |
| 355 | else | 351 | else |
| 356 | buffer[0] = '\0'; | 352 | buffer[0] = '\0'; |
| 357 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); | 353 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); |
| 358 | tomoyo_io_printf(head, "Total: %10u\n", shared + private); | 354 | tomoyo_io_printf(head, "Total: %10u\n", policy); |
| 359 | head->read_eof = true; | 355 | head->read_eof = true; |
| 360 | } | 356 | } |
| 361 | return 0; | 357 | return 0; |
| @@ -373,9 +369,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | |||
| 373 | char *data = head->write_buf; | 369 | char *data = head->write_buf; |
| 374 | unsigned int size; | 370 | unsigned int size; |
| 375 | 371 | ||
| 376 | if (sscanf(data, "Shared: %u", &size) == 1) | 372 | if (sscanf(data, "Policy: %u", &size) == 1) |
| 377 | tomoyo_quota_for_savename = size; | 373 | tomoyo_quota_for_policy = size; |
| 378 | else if (sscanf(data, "Private: %u", &size) == 1) | ||
| 379 | tomoyo_quota_for_elements = size; | ||
| 380 | return 0; | 374 | return 0; |
| 381 | } | 375 | } |
