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