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 14 enum 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 27 struct tomoyo_gc_entry { 28 struct list_head list; 29 int type; 30 void *element; 31 }; 32 static LIST_HEAD(tomoyo_gc_queue); 33 static DEFINE_MUTEX(tomoyo_gc_mutex); 34 35 /* Caller holds tomoyo_policy_lock mutex. */ 36 static 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 47 static void tomoyo_del_allow_read 48 (struct tomoyo_globally_readable_file_entry *ptr) 49 { 50 tomoyo_put_name(ptr->filename); 51 } 52 53 static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) 54 { 55 tomoyo_put_name(ptr->pattern); 56 } 57 58 static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) 59 { 60 tomoyo_put_name(ptr->pattern); 61 } 62 63 static 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 70 static 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 76 static 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 82 static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) 83 { 84 tomoyo_put_name(ptr->manager); 85 } 86 87 static 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 111 static 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 148 static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) 149 { 150 } 151 152 static void tomoyo_collect_entry(void) 153 { 154 mutex_lock(&tomoyo_policy_lock); 155 { 156 struct tomoyo_globally_readable_file_entry *ptr; 157 list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, 158 list) { 159 if (!ptr->is_deleted) 160 continue; 161 if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) 162 list_del_rcu(&ptr->list); 163 else 164 break; 165 } 166 } 167 { 168 struct tomoyo_pattern_entry *ptr; 169 list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { 170 if (!ptr->is_deleted) 171 continue; 172 if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) 173 list_del_rcu(&ptr->list); 174 else 175 break; 176 } 177 } 178 { 179 struct tomoyo_no_rewrite_entry *ptr; 180 list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { 181 if (!ptr->is_deleted) 182 continue; 183 if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) 184 list_del_rcu(&ptr->list); 185 else 186 break; 187 } 188 } 189 { 190 struct tomoyo_domain_initializer_entry *ptr; 191 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, 192 list) { 193 if (!ptr->is_deleted) 194 continue; 195 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) 196 list_del_rcu(&ptr->list); 197 else 198 break; 199 } 200 } 201 { 202 struct tomoyo_domain_keeper_entry *ptr; 203 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { 204 if (!ptr->is_deleted) 205 continue; 206 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) 207 list_del_rcu(&ptr->list); 208 else 209 break; 210 } 211 } 212 { 213 struct tomoyo_alias_entry *ptr; 214 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 215 if (!ptr->is_deleted) 216 continue; 217 if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) 218 list_del_rcu(&ptr->list); 219 else 220 break; 221 } 222 } 223 { 224 struct tomoyo_policy_manager_entry *ptr; 225 list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, 226 list) { 227 if (!ptr->is_deleted) 228 continue; 229 if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) 230 list_del_rcu(&ptr->list); 231 else 232 break; 233 } 234 } 235 { 236 struct tomoyo_domain_info *domain; 237 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 238 struct tomoyo_acl_info *acl; 239 list_for_each_entry_rcu(acl, &domain->acl_info_list, 240 list) { 241 switch (acl->type) { 242 case TOMOYO_TYPE_PATH_ACL: 243 if (container_of(acl, 244 struct tomoyo_path_acl, 245 head)->perm || 246 container_of(acl, 247 struct tomoyo_path_acl, 248 head)->perm_high) 249 continue; 250 break; 251 case TOMOYO_TYPE_PATH2_ACL: 252 if (container_of(acl, 253 struct tomoyo_path2_acl, 254 head)->perm) 255 continue; 256 break; 257 default: 258 continue; 259 } 260 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) 261 list_del_rcu(&acl->list); 262 else 263 break; 264 } 265 if (!domain->is_deleted || atomic_read(&domain->users)) 266 continue; 267 /* 268 * Nobody is referring this domain. But somebody may 269 * refer this domain after successful execve(). 270 * We recheck domain->users after SRCU synchronization. 271 */ 272 if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) 273 list_del_rcu(&domain->list); 274 else 275 break; 276 } 277 } 278 mutex_unlock(&tomoyo_policy_lock); 279 mutex_lock(&tomoyo_name_list_lock); 280 { 281 int i; 282 for (i = 0; i < TOMOYO_MAX_HASH; i++) { 283 struct tomoyo_name_entry *ptr; 284 list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], 285 list) { 286 if (atomic_read(&ptr->users)) 287 continue; 288 if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) 289 list_del_rcu(&ptr->list); 290 else { 291 i = TOMOYO_MAX_HASH; 292 break; 293 } 294 } 295 } 296 } 297 mutex_unlock(&tomoyo_name_list_lock); 298 } 299 300 static void tomoyo_kfree_entry(void) 301 { 302 struct tomoyo_gc_entry *p; 303 struct tomoyo_gc_entry *tmp; 304 305 list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { 306 switch (p->type) { 307 case TOMOYO_ID_DOMAIN_INITIALIZER: 308 tomoyo_del_domain_initializer(p->element); 309 break; 310 case TOMOYO_ID_DOMAIN_KEEPER: 311 tomoyo_del_domain_keeper(p->element); 312 break; 313 case TOMOYO_ID_ALIAS: 314 tomoyo_del_alias(p->element); 315 break; 316 case TOMOYO_ID_GLOBALLY_READABLE: 317 tomoyo_del_allow_read(p->element); 318 break; 319 case TOMOYO_ID_PATTERN: 320 tomoyo_del_file_pattern(p->element); 321 break; 322 case TOMOYO_ID_NO_REWRITE: 323 tomoyo_del_no_rewrite(p->element); 324 break; 325 case TOMOYO_ID_MANAGER: 326 tomoyo_del_manager(p->element); 327 break; 328 case TOMOYO_ID_NAME: 329 tomoyo_del_name(p->element); 330 break; 331 case TOMOYO_ID_ACL: 332 tomoyo_del_acl(p->element); 333 break; 334 case TOMOYO_ID_DOMAIN: 335 if (!tomoyo_del_domain(p->element)) 336 continue; 337 break; 338 default: 339 printk(KERN_WARNING "Unknown type\n"); 340 break; 341 } 342 tomoyo_memory_free(p->element); 343 list_del(&p->list); 344 kfree(p); 345 } 346 } 347 348 static int tomoyo_gc_thread(void *unused) 349 { 350 daemonize("GC for TOMOYO"); 351 if (mutex_trylock(&tomoyo_gc_mutex)) { 352 int i; 353 for (i = 0; i < 10; i++) { 354 tomoyo_collect_entry(); 355 if (list_empty(&tomoyo_gc_queue)) 356 break; 357 synchronize_srcu(&tomoyo_ss); 358 tomoyo_kfree_entry(); 359 } 360 mutex_unlock(&tomoyo_gc_mutex); 361 } 362 do_exit(0); 363 } 364 365 void tomoyo_run_gc(void) 366 { 367 struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, 368 "GC for TOMOYO"); 369 if (!IS_ERR(task)) 370 wake_up_process(task); 371 } 372