gc.c revision 292823814261e085cdcef06b6b691e6c2563fbd4
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_DOMAIN_INITIALIZER, 16 TOMOYO_ID_DOMAIN_KEEPER, 17 TOMOYO_ID_ALIAS, 18 TOMOYO_ID_GLOBALLY_READABLE, 19 TOMOYO_ID_PATTERN, 20 TOMOYO_ID_NO_REWRITE, 21 TOMOYO_ID_MANAGER, 22 TOMOYO_ID_NAME, 23 TOMOYO_ID_ACL, 24 TOMOYO_ID_DOMAIN 25}; 26 27struct tomoyo_gc_entry { 28 struct list_head list; 29 int type; 30 void *element; 31}; 32static LIST_HEAD(tomoyo_gc_queue); 33static DEFINE_MUTEX(tomoyo_gc_mutex); 34 35/* Caller holds tomoyo_policy_lock mutex. */ 36static bool tomoyo_add_to_gc(const int type, void *element) 37{ 38 struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 39 if (!entry) 40 return false; 41 entry->type = type; 42 entry->element = element; 43 list_add(&entry->list, &tomoyo_gc_queue); 44 return true; 45} 46 47static void tomoyo_del_allow_read 48(struct tomoyo_globally_readable_file_entry *ptr) 49{ 50 tomoyo_put_name(ptr->filename); 51} 52 53static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) 54{ 55 tomoyo_put_name(ptr->pattern); 56} 57 58static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) 59{ 60 tomoyo_put_name(ptr->pattern); 61} 62 63static void tomoyo_del_domain_initializer 64(struct tomoyo_domain_initializer_entry *ptr) 65{ 66 tomoyo_put_name(ptr->domainname); 67 tomoyo_put_name(ptr->program); 68} 69 70static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) 71{ 72 tomoyo_put_name(ptr->domainname); 73 tomoyo_put_name(ptr->program); 74} 75 76static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) 77{ 78 tomoyo_put_name(ptr->original_name); 79 tomoyo_put_name(ptr->aliased_name); 80} 81 82static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) 83{ 84 tomoyo_put_name(ptr->manager); 85} 86 87static void tomoyo_del_acl(struct tomoyo_acl_info *acl) 88{ 89 switch (acl->type) { 90 case TOMOYO_TYPE_PATH_ACL: 91 { 92 struct tomoyo_path_acl *entry 93 = container_of(acl, typeof(*entry), head); 94 tomoyo_put_name(entry->filename); 95 } 96 break; 97 case TOMOYO_TYPE_PATH2_ACL: 98 { 99 struct tomoyo_path2_acl *entry 100 = container_of(acl, typeof(*entry), head); 101 tomoyo_put_name(entry->filename1); 102 tomoyo_put_name(entry->filename2); 103 } 104 break; 105 default: 106 printk(KERN_WARNING "Unknown type\n"); 107 break; 108 } 109} 110 111static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) 112{ 113 struct tomoyo_acl_info *acl; 114 struct tomoyo_acl_info *tmp; 115 /* 116 * Since we don't protect whole execve() operation using SRCU, 117 * we need to recheck domain->users at this point. 118 * 119 * (1) Reader starts SRCU section upon execve(). 120 * (2) Reader traverses tomoyo_domain_list and finds this domain. 121 * (3) Writer marks this domain as deleted. 122 * (4) Garbage collector removes this domain from tomoyo_domain_list 123 * because this domain is marked as deleted and used by nobody. 124 * (5) Reader saves reference to this domain into 125 * "struct linux_binprm"->cred->security . 126 * (6) Reader finishes SRCU section, although execve() operation has 127 * not finished yet. 128 * (7) Garbage collector waits for SRCU synchronization. 129 * (8) Garbage collector kfree() this domain because this domain is 130 * used by nobody. 131 * (9) Reader finishes execve() operation and restores this domain from 132 * "struct linux_binprm"->cred->security. 133 * 134 * By updating domain->users at (5), we can solve this race problem 135 * by rechecking domain->users at (8). 136 */ 137 if (atomic_read(&domain->users)) 138 return false; 139 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { 140 tomoyo_del_acl(acl); 141 tomoyo_memory_free(acl); 142 } 143 tomoyo_put_name(domain->domainname); 144 return true; 145} 146 147 148static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) 149{ 150} 151 152static void tomoyo_collect_entry(void) 153{ 154 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 155 return; 156 { 157 struct tomoyo_globally_readable_file_entry *ptr; 158 list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 159 list) { 160 if (!ptr->is_deleted) 161 continue; 162 if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) 163 list_del_rcu(&ptr->list); 164 else 165 break; 166 } 167 } 168 { 169 struct tomoyo_pattern_entry *ptr; 170 list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 171 if (!ptr->is_deleted) 172 continue; 173 if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) 174 list_del_rcu(&ptr->list); 175 else 176 break; 177 } 178 } 179 { 180 struct tomoyo_no_rewrite_entry *ptr; 181 list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 182 if (!ptr->is_deleted) 183 continue; 184 if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) 185 list_del_rcu(&ptr->list); 186 else 187 break; 188 } 189 } 190 { 191 struct tomoyo_domain_initializer_entry *ptr; 192 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, 193 list) { 194 if (!ptr->is_deleted) 195 continue; 196 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) 197 list_del_rcu(&ptr->list); 198 else 199 break; 200 } 201 } 202 { 203 struct tomoyo_domain_keeper_entry *ptr; 204 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { 205 if (!ptr->is_deleted) 206 continue; 207 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) 208 list_del_rcu(&ptr->list); 209 else 210 break; 211 } 212 } 213 { 214 struct tomoyo_alias_entry *ptr; 215 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 216 if (!ptr->is_deleted) 217 continue; 218 if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) 219 list_del_rcu(&ptr->list); 220 else 221 break; 222 } 223 } 224 { 225 struct tomoyo_policy_manager_entry *ptr; 226 list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, 227 list) { 228 if (!ptr->is_deleted) 229 continue; 230 if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) 231 list_del_rcu(&ptr->list); 232 else 233 break; 234 } 235 } 236 { 237 struct tomoyo_domain_info *domain; 238 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 239 struct tomoyo_acl_info *acl; 240 list_for_each_entry_rcu(acl, &domain->acl_info_list, 241 list) { 242 switch (acl->type) { 243 case TOMOYO_TYPE_PATH_ACL: 244 if (container_of(acl, 245 struct tomoyo_path_acl, 246 head)->perm || 247 container_of(acl, 248 struct tomoyo_path_acl, 249 head)->perm_high) 250 continue; 251 break; 252 case TOMOYO_TYPE_PATH2_ACL: 253 if (container_of(acl, 254 struct tomoyo_path2_acl, 255 head)->perm) 256 continue; 257 break; 258 default: 259 continue; 260 } 261 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) 262 list_del_rcu(&acl->list); 263 else 264 break; 265 } 266 if (!domain->is_deleted || atomic_read(&domain->users)) 267 continue; 268 /* 269 * Nobody is referring this domain. But somebody may 270 * refer this domain after successful execve(). 271 * We recheck domain->users after SRCU synchronization. 272 */ 273 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) 274 list_del_rcu(&domain->list); 275 else 276 break; 277 } 278 } 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_policy_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