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