gc.c revision a1f9bb6a375a8dbf7797ffbd6739c46b338a77f7
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#include <linux/slab.h> 13 14enum tomoyo_gc_id { 15 TOMOYO_ID_PATH_GROUP, 16 TOMOYO_ID_PATH_GROUP_MEMBER, 17 TOMOYO_ID_NUMBER_GROUP, 18 TOMOYO_ID_NUMBER_GROUP_MEMBER, 19 TOMOYO_ID_DOMAIN_INITIALIZER, 20 TOMOYO_ID_DOMAIN_KEEPER, 21 TOMOYO_ID_ALIAS, 22 TOMOYO_ID_GLOBALLY_READABLE, 23 TOMOYO_ID_PATTERN, 24 TOMOYO_ID_NO_REWRITE, 25 TOMOYO_ID_MANAGER, 26 TOMOYO_ID_NAME, 27 TOMOYO_ID_ACL, 28 TOMOYO_ID_DOMAIN 29}; 30 31struct tomoyo_gc_entry { 32 struct list_head list; 33 int type; 34 void *element; 35}; 36static LIST_HEAD(tomoyo_gc_queue); 37static DEFINE_MUTEX(tomoyo_gc_mutex); 38 39/* Caller holds tomoyo_policy_lock mutex. */ 40static bool tomoyo_add_to_gc(const int type, void *element) 41{ 42 struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 43 if (!entry) 44 return false; 45 entry->type = type; 46 entry->element = element; 47 list_add(&entry->list, &tomoyo_gc_queue); 48 return true; 49} 50 51static void tomoyo_del_allow_read 52(struct tomoyo_globally_readable_file_entry *ptr) 53{ 54 tomoyo_put_name(ptr->filename); 55} 56 57static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) 58{ 59 tomoyo_put_name(ptr->pattern); 60} 61 62static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) 63{ 64 tomoyo_put_name(ptr->pattern); 65} 66 67static void tomoyo_del_domain_initializer 68(struct tomoyo_domain_initializer_entry *ptr) 69{ 70 tomoyo_put_name(ptr->domainname); 71 tomoyo_put_name(ptr->program); 72} 73 74static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) 75{ 76 tomoyo_put_name(ptr->domainname); 77 tomoyo_put_name(ptr->program); 78} 79 80static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) 81{ 82 tomoyo_put_name(ptr->original_name); 83 tomoyo_put_name(ptr->aliased_name); 84} 85 86static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) 87{ 88 tomoyo_put_name(ptr->manager); 89} 90 91static void tomoyo_del_acl(struct tomoyo_acl_info *acl) 92{ 93 switch (acl->type) { 94 case TOMOYO_TYPE_PATH_ACL: 95 { 96 struct tomoyo_path_acl *entry 97 = container_of(acl, typeof(*entry), head); 98 tomoyo_put_name_union(&entry->name); 99 } 100 break; 101 case TOMOYO_TYPE_PATH2_ACL: 102 { 103 struct tomoyo_path2_acl *entry 104 = container_of(acl, typeof(*entry), head); 105 tomoyo_put_name_union(&entry->name1); 106 tomoyo_put_name_union(&entry->name2); 107 } 108 break; 109 case TOMOYO_TYPE_PATH_NUMBER_ACL: 110 { 111 struct tomoyo_path_number_acl *entry 112 = container_of(acl, typeof(*entry), head); 113 tomoyo_put_name_union(&entry->name); 114 tomoyo_put_number_union(&entry->number); 115 } 116 break; 117 case TOMOYO_TYPE_PATH_NUMBER3_ACL: 118 { 119 struct tomoyo_path_number3_acl *entry 120 = container_of(acl, typeof(*entry), head); 121 tomoyo_put_name_union(&entry->name); 122 tomoyo_put_number_union(&entry->mode); 123 tomoyo_put_number_union(&entry->major); 124 tomoyo_put_number_union(&entry->minor); 125 } 126 break; 127 default: 128 printk(KERN_WARNING "Unknown type\n"); 129 break; 130 } 131} 132 133static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) 134{ 135 struct tomoyo_acl_info *acl; 136 struct tomoyo_acl_info *tmp; 137 /* 138 * Since we don't protect whole execve() operation using SRCU, 139 * we need to recheck domain->users at this point. 140 * 141 * (1) Reader starts SRCU section upon execve(). 142 * (2) Reader traverses tomoyo_domain_list and finds this domain. 143 * (3) Writer marks this domain as deleted. 144 * (4) Garbage collector removes this domain from tomoyo_domain_list 145 * because this domain is marked as deleted and used by nobody. 146 * (5) Reader saves reference to this domain into 147 * "struct linux_binprm"->cred->security . 148 * (6) Reader finishes SRCU section, although execve() operation has 149 * not finished yet. 150 * (7) Garbage collector waits for SRCU synchronization. 151 * (8) Garbage collector kfree() this domain because this domain is 152 * used by nobody. 153 * (9) Reader finishes execve() operation and restores this domain from 154 * "struct linux_binprm"->cred->security. 155 * 156 * By updating domain->users at (5), we can solve this race problem 157 * by rechecking domain->users at (8). 158 */ 159 if (atomic_read(&domain->users)) 160 return false; 161 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { 162 tomoyo_del_acl(acl); 163 tomoyo_memory_free(acl); 164 } 165 tomoyo_put_name(domain->domainname); 166 return true; 167} 168 169 170static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) 171{ 172} 173 174static void tomoyo_del_path_group_member(struct tomoyo_path_group_member 175 *member) 176{ 177 tomoyo_put_name(member->member_name); 178} 179 180static void tomoyo_del_path_group(struct tomoyo_path_group *group) 181{ 182 tomoyo_put_name(group->group_name); 183} 184 185static void tomoyo_del_number_group_member(struct tomoyo_number_group_member 186 *member) 187{ 188} 189 190static void tomoyo_del_number_group(struct tomoyo_number_group *group) 191{ 192 tomoyo_put_name(group->group_name); 193} 194 195static void tomoyo_collect_entry(void) 196{ 197 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 198 return; 199 { 200 struct tomoyo_globally_readable_file_entry *ptr; 201 list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 202 list) { 203 if (!ptr->is_deleted) 204 continue; 205 if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) 206 list_del_rcu(&ptr->list); 207 else 208 break; 209 } 210 } 211 { 212 struct tomoyo_pattern_entry *ptr; 213 list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 214 if (!ptr->is_deleted) 215 continue; 216 if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) 217 list_del_rcu(&ptr->list); 218 else 219 break; 220 } 221 } 222 { 223 struct tomoyo_no_rewrite_entry *ptr; 224 list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 225 if (!ptr->is_deleted) 226 continue; 227 if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) 228 list_del_rcu(&ptr->list); 229 else 230 break; 231 } 232 } 233 { 234 struct tomoyo_domain_initializer_entry *ptr; 235 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, 236 list) { 237 if (!ptr->is_deleted) 238 continue; 239 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) 240 list_del_rcu(&ptr->list); 241 else 242 break; 243 } 244 } 245 { 246 struct tomoyo_domain_keeper_entry *ptr; 247 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { 248 if (!ptr->is_deleted) 249 continue; 250 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) 251 list_del_rcu(&ptr->list); 252 else 253 break; 254 } 255 } 256 { 257 struct tomoyo_alias_entry *ptr; 258 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 259 if (!ptr->is_deleted) 260 continue; 261 if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) 262 list_del_rcu(&ptr->list); 263 else 264 break; 265 } 266 } 267 { 268 struct tomoyo_policy_manager_entry *ptr; 269 list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, 270 list) { 271 if (!ptr->is_deleted) 272 continue; 273 if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) 274 list_del_rcu(&ptr->list); 275 else 276 break; 277 } 278 } 279 { 280 struct tomoyo_domain_info *domain; 281 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 282 struct tomoyo_acl_info *acl; 283 list_for_each_entry_rcu(acl, &domain->acl_info_list, 284 list) { 285 switch (acl->type) { 286 case TOMOYO_TYPE_PATH_ACL: 287 if (container_of(acl, 288 struct tomoyo_path_acl, 289 head)->perm) 290 continue; 291 break; 292 case TOMOYO_TYPE_PATH2_ACL: 293 if (container_of(acl, 294 struct tomoyo_path2_acl, 295 head)->perm) 296 continue; 297 break; 298 case TOMOYO_TYPE_PATH_NUMBER_ACL: 299 if (container_of(acl, 300 struct tomoyo_path_number_acl, 301 head)->perm) 302 continue; 303 break; 304 case TOMOYO_TYPE_PATH_NUMBER3_ACL: 305 if (container_of(acl, 306 struct tomoyo_path_number3_acl, 307 head)->perm) 308 continue; 309 break; 310 default: 311 continue; 312 } 313 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) 314 list_del_rcu(&acl->list); 315 else 316 break; 317 } 318 if (!domain->is_deleted || atomic_read(&domain->users)) 319 continue; 320 /* 321 * Nobody is referring this domain. But somebody may 322 * refer this domain after successful execve(). 323 * We recheck domain->users after SRCU synchronization. 324 */ 325 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) 326 list_del_rcu(&domain->list); 327 else 328 break; 329 } 330 } 331 { 332 int i; 333 for (i = 0; i < TOMOYO_MAX_HASH; i++) { 334 struct tomoyo_name_entry *ptr; 335 list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], 336 list) { 337 if (atomic_read(&ptr->users)) 338 continue; 339 if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) 340 list_del_rcu(&ptr->list); 341 else { 342 i = TOMOYO_MAX_HASH; 343 break; 344 } 345 } 346 } 347 } 348 { 349 struct tomoyo_path_group *group; 350 list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) { 351 struct tomoyo_path_group_member *member; 352 list_for_each_entry_rcu(member, &group->member_list, 353 list) { 354 if (!member->is_deleted) 355 continue; 356 if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER, 357 member)) 358 list_del_rcu(&member->list); 359 else 360 break; 361 } 362 if (!list_empty(&group->member_list) || 363 atomic_read(&group->users)) 364 continue; 365 if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group)) 366 list_del_rcu(&group->list); 367 else 368 break; 369 } 370 } 371 { 372 struct tomoyo_number_group *group; 373 list_for_each_entry_rcu(group, &tomoyo_number_group_list, list) { 374 struct tomoyo_number_group_member *member; 375 list_for_each_entry_rcu(member, &group->member_list, 376 list) { 377 if (!member->is_deleted) 378 continue; 379 if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP_MEMBER, 380 member)) 381 list_del_rcu(&member->list); 382 else 383 break; 384 } 385 if (!list_empty(&group->member_list) || 386 atomic_read(&group->users)) 387 continue; 388 if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP, group)) 389 list_del_rcu(&group->list); 390 else 391 break; 392 } 393 } 394 mutex_unlock(&tomoyo_policy_lock); 395} 396 397static void tomoyo_kfree_entry(void) 398{ 399 struct tomoyo_gc_entry *p; 400 struct tomoyo_gc_entry *tmp; 401 402 list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { 403 switch (p->type) { 404 case TOMOYO_ID_DOMAIN_INITIALIZER: 405 tomoyo_del_domain_initializer(p->element); 406 break; 407 case TOMOYO_ID_DOMAIN_KEEPER: 408 tomoyo_del_domain_keeper(p->element); 409 break; 410 case TOMOYO_ID_ALIAS: 411 tomoyo_del_alias(p->element); 412 break; 413 case TOMOYO_ID_GLOBALLY_READABLE: 414 tomoyo_del_allow_read(p->element); 415 break; 416 case TOMOYO_ID_PATTERN: 417 tomoyo_del_file_pattern(p->element); 418 break; 419 case TOMOYO_ID_NO_REWRITE: 420 tomoyo_del_no_rewrite(p->element); 421 break; 422 case TOMOYO_ID_MANAGER: 423 tomoyo_del_manager(p->element); 424 break; 425 case TOMOYO_ID_NAME: 426 tomoyo_del_name(p->element); 427 break; 428 case TOMOYO_ID_ACL: 429 tomoyo_del_acl(p->element); 430 break; 431 case TOMOYO_ID_DOMAIN: 432 if (!tomoyo_del_domain(p->element)) 433 continue; 434 break; 435 case TOMOYO_ID_PATH_GROUP_MEMBER: 436 tomoyo_del_path_group_member(p->element); 437 break; 438 case TOMOYO_ID_PATH_GROUP: 439 tomoyo_del_path_group(p->element); 440 break; 441 case TOMOYO_ID_NUMBER_GROUP_MEMBER: 442 tomoyo_del_number_group_member(p->element); 443 break; 444 case TOMOYO_ID_NUMBER_GROUP: 445 tomoyo_del_number_group(p->element); 446 break; 447 default: 448 printk(KERN_WARNING "Unknown type\n"); 449 break; 450 } 451 tomoyo_memory_free(p->element); 452 list_del(&p->list); 453 kfree(p); 454 } 455} 456 457static int tomoyo_gc_thread(void *unused) 458{ 459 daemonize("GC for TOMOYO"); 460 if (mutex_trylock(&tomoyo_gc_mutex)) { 461 int i; 462 for (i = 0; i < 10; i++) { 463 tomoyo_collect_entry(); 464 if (list_empty(&tomoyo_gc_queue)) 465 break; 466 synchronize_srcu(&tomoyo_ss); 467 tomoyo_kfree_entry(); 468 } 469 mutex_unlock(&tomoyo_gc_mutex); 470 } 471 do_exit(0); 472} 473 474void tomoyo_run_gc(void) 475{ 476 struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, 477 "GC for TOMOYO"); 478 if (!IS_ERR(task)) 479 wake_up_process(task); 480} 481