gc.c revision bd03a3e4c9a9df0c6b007045fa7fc8889111a478
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 14struct tomoyo_gc { 15 struct list_head list; 16 enum tomoyo_policy_id type; 17 struct list_head *element; 18}; 19static LIST_HEAD(tomoyo_gc_queue); 20static DEFINE_MUTEX(tomoyo_gc_mutex); 21 22/** 23 * tomoyo_add_to_gc - Add an entry to to be deleted list. 24 * 25 * @type: One of values in "enum tomoyo_policy_id". 26 * @element: Pointer to "struct list_head". 27 * 28 * Returns true on success, false otherwise. 29 * 30 * Caller holds tomoyo_policy_lock mutex. 31 * 32 * Adding an entry needs kmalloc(). Thus, if we try to add thousands of 33 * entries at once, it will take too long time. Thus, do not add more than 128 34 * entries per a scan. But to be able to handle worst case where all entries 35 * are in-use, we accept one more entry per a scan. 36 * 37 * If we use singly linked list using "struct list_head"->prev (which is 38 * LIST_POISON2), we can avoid kmalloc(). 39 */ 40static bool tomoyo_add_to_gc(const int type, struct list_head *element) 41{ 42 struct tomoyo_gc *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 list_del_rcu(element); 49 return true; 50} 51 52/** 53 * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control". 54 * 55 * @element: Pointer to "struct list_head". 56 * 57 * Returns nothing. 58 */ 59static void tomoyo_del_transition_control(struct list_head *element) 60{ 61 struct tomoyo_transition_control *ptr = 62 container_of(element, typeof(*ptr), head.list); 63 tomoyo_put_name(ptr->domainname); 64 tomoyo_put_name(ptr->program); 65} 66 67/** 68 * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator". 69 * 70 * @element: Pointer to "struct list_head". 71 * 72 * Returns nothing. 73 */ 74static void tomoyo_del_aggregator(struct list_head *element) 75{ 76 struct tomoyo_aggregator *ptr = 77 container_of(element, typeof(*ptr), head.list); 78 tomoyo_put_name(ptr->original_name); 79 tomoyo_put_name(ptr->aggregated_name); 80} 81 82/** 83 * tomoyo_del_manager - Delete members in "struct tomoyo_manager". 84 * 85 * @element: Pointer to "struct list_head". 86 * 87 * Returns nothing. 88 */ 89static void tomoyo_del_manager(struct list_head *element) 90{ 91 struct tomoyo_manager *ptr = 92 container_of(element, typeof(*ptr), head.list); 93 tomoyo_put_name(ptr->manager); 94} 95 96/** 97 * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info". 98 * 99 * @element: Pointer to "struct list_head". 100 * 101 * Returns nothing. 102 */ 103static void tomoyo_del_acl(struct list_head *element) 104{ 105 struct tomoyo_acl_info *acl = 106 container_of(element, typeof(*acl), list); 107 switch (acl->type) { 108 case TOMOYO_TYPE_PATH_ACL: 109 { 110 struct tomoyo_path_acl *entry 111 = container_of(acl, typeof(*entry), head); 112 tomoyo_put_name_union(&entry->name); 113 } 114 break; 115 case TOMOYO_TYPE_PATH2_ACL: 116 { 117 struct tomoyo_path2_acl *entry 118 = container_of(acl, typeof(*entry), head); 119 tomoyo_put_name_union(&entry->name1); 120 tomoyo_put_name_union(&entry->name2); 121 } 122 break; 123 case TOMOYO_TYPE_PATH_NUMBER_ACL: 124 { 125 struct tomoyo_path_number_acl *entry 126 = container_of(acl, typeof(*entry), head); 127 tomoyo_put_name_union(&entry->name); 128 tomoyo_put_number_union(&entry->number); 129 } 130 break; 131 case TOMOYO_TYPE_MKDEV_ACL: 132 { 133 struct tomoyo_mkdev_acl *entry 134 = container_of(acl, typeof(*entry), head); 135 tomoyo_put_name_union(&entry->name); 136 tomoyo_put_number_union(&entry->mode); 137 tomoyo_put_number_union(&entry->major); 138 tomoyo_put_number_union(&entry->minor); 139 } 140 break; 141 case TOMOYO_TYPE_MOUNT_ACL: 142 { 143 struct tomoyo_mount_acl *entry 144 = container_of(acl, typeof(*entry), head); 145 tomoyo_put_name_union(&entry->dev_name); 146 tomoyo_put_name_union(&entry->dir_name); 147 tomoyo_put_name_union(&entry->fs_type); 148 tomoyo_put_number_union(&entry->flags); 149 } 150 break; 151 } 152} 153 154static bool tomoyo_del_domain(struct list_head *element) 155{ 156 struct tomoyo_domain_info *domain = 157 container_of(element, typeof(*domain), list); 158 struct tomoyo_acl_info *acl; 159 struct tomoyo_acl_info *tmp; 160 /* 161 * Since we don't protect whole execve() operation using SRCU, 162 * we need to recheck domain->users at this point. 163 * 164 * (1) Reader starts SRCU section upon execve(). 165 * (2) Reader traverses tomoyo_domain_list and finds this domain. 166 * (3) Writer marks this domain as deleted. 167 * (4) Garbage collector removes this domain from tomoyo_domain_list 168 * because this domain is marked as deleted and used by nobody. 169 * (5) Reader saves reference to this domain into 170 * "struct linux_binprm"->cred->security . 171 * (6) Reader finishes SRCU section, although execve() operation has 172 * not finished yet. 173 * (7) Garbage collector waits for SRCU synchronization. 174 * (8) Garbage collector kfree() this domain because this domain is 175 * used by nobody. 176 * (9) Reader finishes execve() operation and restores this domain from 177 * "struct linux_binprm"->cred->security. 178 * 179 * By updating domain->users at (5), we can solve this race problem 180 * by rechecking domain->users at (8). 181 */ 182 if (atomic_read(&domain->users)) 183 return false; 184 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { 185 tomoyo_del_acl(&acl->list); 186 tomoyo_memory_free(acl); 187 } 188 tomoyo_put_name(domain->domainname); 189 return true; 190} 191 192 193/** 194 * tomoyo_del_name - Delete members in "struct tomoyo_name". 195 * 196 * @element: Pointer to "struct list_head". 197 * 198 * Returns nothing. 199 */ 200static void tomoyo_del_name(struct list_head *element) 201{ 202 const struct tomoyo_name *ptr = 203 container_of(element, typeof(*ptr), head.list); 204} 205 206/** 207 * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group". 208 * 209 * @element: Pointer to "struct list_head". 210 * 211 * Returns nothing. 212 */ 213static void tomoyo_del_path_group(struct list_head *element) 214{ 215 struct tomoyo_path_group *member = 216 container_of(element, typeof(*member), head.list); 217 tomoyo_put_name(member->member_name); 218} 219 220/** 221 * tomoyo_del_group - Delete "struct tomoyo_group". 222 * 223 * @element: Pointer to "struct list_head". 224 * 225 * Returns nothing. 226 */ 227static void tomoyo_del_group(struct list_head *element) 228{ 229 struct tomoyo_group *group = 230 container_of(element, typeof(*group), head.list); 231 tomoyo_put_name(group->group_name); 232} 233 234/** 235 * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group". 236 * 237 * @element: Pointer to "struct list_head". 238 * 239 * Returns nothing. 240 */ 241static void tomoyo_del_number_group(struct list_head *element) 242{ 243 struct tomoyo_number_group *member = 244 container_of(element, typeof(*member), head.list); 245} 246 247/** 248 * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head". 249 * 250 * @id: One of values in "enum tomoyo_policy_id". 251 * @member_list: Pointer to "struct list_head". 252 * 253 * Returns true if some elements are deleted, false otherwise. 254 */ 255static bool tomoyo_collect_member(const enum tomoyo_policy_id id, 256 struct list_head *member_list) 257{ 258 struct tomoyo_acl_head *member; 259 list_for_each_entry(member, member_list, list) { 260 if (!member->is_deleted) 261 continue; 262 if (!tomoyo_add_to_gc(id, &member->list)) 263 return false; 264 } 265 return true; 266} 267 268/** 269 * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info". 270 * 271 * @list: Pointer to "struct list_head". 272 * 273 * Returns true if some elements are deleted, false otherwise. 274 */ 275static bool tomoyo_collect_acl(struct list_head *list) 276{ 277 struct tomoyo_acl_info *acl; 278 list_for_each_entry(acl, list, list) { 279 if (!acl->is_deleted) 280 continue; 281 if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list)) 282 return false; 283 } 284 return true; 285} 286 287/** 288 * tomoyo_collect_entry - Scan lists for deleted elements. 289 * 290 * Returns nothing. 291 */ 292static void tomoyo_collect_entry(void) 293{ 294 int i; 295 enum tomoyo_policy_id id; 296 struct tomoyo_policy_namespace *ns; 297 int idx; 298 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 299 return; 300 idx = tomoyo_read_lock(); 301 { 302 struct tomoyo_domain_info *domain; 303 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 304 if (!tomoyo_collect_acl(&domain->acl_info_list)) 305 goto unlock; 306 if (!domain->is_deleted || atomic_read(&domain->users)) 307 continue; 308 /* 309 * Nobody is referring this domain. But somebody may 310 * refer this domain after successful execve(). 311 * We recheck domain->users after SRCU synchronization. 312 */ 313 if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list)) 314 goto unlock; 315 } 316 } 317 list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) { 318 for (id = 0; id < TOMOYO_MAX_POLICY; id++) 319 if (!tomoyo_collect_member(id, &ns->policy_list[id])) 320 goto unlock; 321 for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++) 322 if (!tomoyo_collect_acl(&ns->acl_group[i])) 323 goto unlock; 324 for (i = 0; i < TOMOYO_MAX_GROUP; i++) { 325 struct list_head *list = &ns->group_list[i]; 326 struct tomoyo_group *group; 327 switch (i) { 328 case 0: 329 id = TOMOYO_ID_PATH_GROUP; 330 break; 331 default: 332 id = TOMOYO_ID_NUMBER_GROUP; 333 break; 334 } 335 list_for_each_entry(group, list, head.list) { 336 if (!tomoyo_collect_member 337 (id, &group->member_list)) 338 goto unlock; 339 if (!list_empty(&group->member_list) || 340 atomic_read(&group->head.users)) 341 continue; 342 if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, 343 &group->head.list)) 344 goto unlock; 345 } 346 } 347 } 348 for (i = 0; i < TOMOYO_MAX_HASH; i++) { 349 struct list_head *list = &tomoyo_name_list[i]; 350 struct tomoyo_shared_acl_head *ptr; 351 list_for_each_entry(ptr, list, list) { 352 if (atomic_read(&ptr->users)) 353 continue; 354 if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list)) 355 goto unlock; 356 } 357 } 358unlock: 359 tomoyo_read_unlock(idx); 360 mutex_unlock(&tomoyo_policy_lock); 361} 362 363static void tomoyo_kfree_entry(void) 364{ 365 struct tomoyo_gc *p; 366 struct tomoyo_gc *tmp; 367 368 list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { 369 struct list_head *element = p->element; 370 switch (p->type) { 371 case TOMOYO_ID_TRANSITION_CONTROL: 372 tomoyo_del_transition_control(element); 373 break; 374 case TOMOYO_ID_AGGREGATOR: 375 tomoyo_del_aggregator(element); 376 break; 377 case TOMOYO_ID_MANAGER: 378 tomoyo_del_manager(element); 379 break; 380 case TOMOYO_ID_NAME: 381 tomoyo_del_name(element); 382 break; 383 case TOMOYO_ID_ACL: 384 tomoyo_del_acl(element); 385 break; 386 case TOMOYO_ID_DOMAIN: 387 if (!tomoyo_del_domain(element)) 388 continue; 389 break; 390 case TOMOYO_ID_PATH_GROUP: 391 tomoyo_del_path_group(element); 392 break; 393 case TOMOYO_ID_GROUP: 394 tomoyo_del_group(element); 395 break; 396 case TOMOYO_ID_NUMBER_GROUP: 397 tomoyo_del_number_group(element); 398 break; 399 case TOMOYO_MAX_POLICY: 400 break; 401 } 402 tomoyo_memory_free(element); 403 list_del(&p->list); 404 kfree(p); 405 } 406} 407 408/** 409 * tomoyo_gc_thread - Garbage collector thread function. 410 * 411 * @unused: Unused. 412 * 413 * In case OOM-killer choose this thread for termination, we create this thread 414 * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was 415 * close()d. 416 * 417 * Returns 0. 418 */ 419static int tomoyo_gc_thread(void *unused) 420{ 421 daemonize("GC for TOMOYO"); 422 if (mutex_trylock(&tomoyo_gc_mutex)) { 423 int i; 424 for (i = 0; i < 10; i++) { 425 tomoyo_collect_entry(); 426 if (list_empty(&tomoyo_gc_queue)) 427 break; 428 synchronize_srcu(&tomoyo_ss); 429 tomoyo_kfree_entry(); 430 } 431 mutex_unlock(&tomoyo_gc_mutex); 432 } 433 do_exit(0); 434} 435 436void tomoyo_run_gc(void) 437{ 438 struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, 439 "GC for TOMOYO"); 440 if (!IS_ERR(task)) 441 wake_up_process(task); 442} 443