gc.c revision 847b173ea3d6f50936823d07f2245059bf44713b
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 13enum 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 26struct tomoyo_gc_entry { 27 struct list_head list; 28 int type; 29 void *element; 30}; 31static LIST_HEAD(tomoyo_gc_queue); 32static DEFINE_MUTEX(tomoyo_gc_mutex); 33 34/* Caller holds tomoyo_policy_lock mutex. */ 35static 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 46static void tomoyo_del_allow_read 47(struct tomoyo_globally_readable_file_entry *ptr) 48{ 49 tomoyo_put_name(ptr->filename); 50} 51 52static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) 53{ 54 tomoyo_put_name(ptr->pattern); 55} 56 57static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) 58{ 59 tomoyo_put_name(ptr->pattern); 60} 61 62static 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 69static 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 75static 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 81static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) 82{ 83 tomoyo_put_name(ptr->manager); 84} 85 86static 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 110static 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 147static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) 148{ 149} 150 151static 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 299static 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 347static 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 364void 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} 371