domain.c revision 0617c7ff34dc9b1d641640c3953274bb2dbe21a6
1/* 2 * security/tomoyo/domain.c 3 * 4 * Domain transition functions for TOMOYO. 5 * 6 * Copyright (C) 2005-2010 NTT DATA CORPORATION 7 */ 8 9#include "common.h" 10#include <linux/binfmts.h> 11#include <linux/slab.h> 12 13/* Variables definitions.*/ 14 15/* The initial domain. */ 16struct tomoyo_domain_info tomoyo_kernel_domain; 17 18/** 19 * tomoyo_update_policy - Update an entry for exception policy. 20 * 21 * @new_entry: Pointer to "struct tomoyo_acl_info". 22 * @size: Size of @new_entry in bytes. 23 * @is_delete: True if it is a delete request. 24 * @list: Pointer to "struct list_head". 25 * @check_duplicate: Callback function to find duplicated entry. 26 * 27 * Returns 0 on success, negative value otherwise. 28 * 29 * Caller holds tomoyo_read_lock(). 30 */ 31int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, 32 bool is_delete, struct list_head *list, 33 bool (*check_duplicate) (const struct tomoyo_acl_head 34 *, 35 const struct tomoyo_acl_head 36 *)) 37{ 38 int error = is_delete ? -ENOENT : -ENOMEM; 39 struct tomoyo_acl_head *entry; 40 41 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 42 return -ENOMEM; 43 list_for_each_entry_rcu(entry, list, list) { 44 if (!check_duplicate(entry, new_entry)) 45 continue; 46 entry->is_deleted = is_delete; 47 error = 0; 48 break; 49 } 50 if (error && !is_delete) { 51 entry = tomoyo_commit_ok(new_entry, size); 52 if (entry) { 53 list_add_tail_rcu(&entry->list, list); 54 error = 0; 55 } 56 } 57 mutex_unlock(&tomoyo_policy_lock); 58 return error; 59} 60 61/** 62 * tomoyo_update_domain - Update an entry for domain policy. 63 * 64 * @new_entry: Pointer to "struct tomoyo_acl_info". 65 * @size: Size of @new_entry in bytes. 66 * @is_delete: True if it is a delete request. 67 * @domain: Pointer to "struct tomoyo_domain_info". 68 * @check_duplicate: Callback function to find duplicated entry. 69 * @merge_duplicate: Callback function to merge duplicated entry. 70 * 71 * Returns 0 on success, negative value otherwise. 72 * 73 * Caller holds tomoyo_read_lock(). 74 */ 75int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, 76 bool is_delete, struct tomoyo_domain_info *domain, 77 bool (*check_duplicate) (const struct tomoyo_acl_info 78 *, 79 const struct tomoyo_acl_info 80 *), 81 bool (*merge_duplicate) (struct tomoyo_acl_info *, 82 struct tomoyo_acl_info *, 83 const bool)) 84{ 85 int error = is_delete ? -ENOENT : -ENOMEM; 86 struct tomoyo_acl_info *entry; 87 88 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 89 return error; 90 list_for_each_entry_rcu(entry, &domain->acl_info_list, list) { 91 if (!check_duplicate(entry, new_entry)) 92 continue; 93 if (merge_duplicate) 94 entry->is_deleted = merge_duplicate(entry, new_entry, 95 is_delete); 96 else 97 entry->is_deleted = is_delete; 98 error = 0; 99 break; 100 } 101 if (error && !is_delete) { 102 entry = tomoyo_commit_ok(new_entry, size); 103 if (entry) { 104 list_add_tail_rcu(&entry->list, &domain->acl_info_list); 105 error = 0; 106 } 107 } 108 mutex_unlock(&tomoyo_policy_lock); 109 return error; 110} 111 112void tomoyo_check_acl(struct tomoyo_request_info *r, 113 bool (*check_entry) (const struct tomoyo_request_info *, 114 const struct tomoyo_acl_info *)) 115{ 116 const struct tomoyo_domain_info *domain = r->domain; 117 struct tomoyo_acl_info *ptr; 118 119 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 120 if (ptr->is_deleted || ptr->type != r->param_type) 121 continue; 122 if (check_entry(r, ptr)) { 123 r->granted = true; 124 return; 125 } 126 } 127 r->granted = false; 128} 129 130/* The list for "struct tomoyo_domain_info". */ 131LIST_HEAD(tomoyo_domain_list); 132 133struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; 134struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; 135 136/** 137 * tomoyo_get_last_name - Get last component of a domainname. 138 * 139 * @domain: Pointer to "struct tomoyo_domain_info". 140 * 141 * Returns the last component of the domainname. 142 */ 143const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) 144{ 145 const char *cp0 = domain->domainname->name; 146 const char *cp1 = strrchr(cp0, ' '); 147 148 if (cp1) 149 return cp1 + 1; 150 return cp0; 151} 152 153static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head * 154 a, 155 const struct tomoyo_acl_head * 156 b) 157{ 158 const struct tomoyo_domain_initializer_entry *p1 = 159 container_of(a, typeof(*p1), head); 160 const struct tomoyo_domain_initializer_entry *p2 = 161 container_of(b, typeof(*p2), head); 162 return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name 163 && p1->domainname == p2->domainname 164 && p1->program == p2->program; 165} 166 167/** 168 * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. 169 * 170 * @domainname: The name of domain. May be NULL. 171 * @program: The name of program. 172 * @is_not: True if it is "no_initialize_domain" entry. 173 * @is_delete: True if it is a delete request. 174 * 175 * Returns 0 on success, negative value otherwise. 176 * 177 * Caller holds tomoyo_read_lock(). 178 */ 179static int tomoyo_update_domain_initializer_entry(const char *domainname, 180 const char *program, 181 const bool is_not, 182 const bool is_delete) 183{ 184 struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; 185 int error = is_delete ? -ENOENT : -ENOMEM; 186 187 if (!tomoyo_correct_path(program)) 188 return -EINVAL; 189 if (domainname) { 190 if (!tomoyo_domain_def(domainname) && 191 tomoyo_correct_path(domainname)) 192 e.is_last_name = true; 193 else if (!tomoyo_correct_domain(domainname)) 194 return -EINVAL; 195 e.domainname = tomoyo_get_name(domainname); 196 if (!e.domainname) 197 goto out; 198 } 199 e.program = tomoyo_get_name(program); 200 if (!e.program) 201 goto out; 202 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 203 &tomoyo_policy_list 204 [TOMOYO_ID_DOMAIN_INITIALIZER], 205 tomoyo_same_domain_initializer_entry); 206 out: 207 tomoyo_put_name(e.domainname); 208 tomoyo_put_name(e.program); 209 return error; 210} 211 212/** 213 * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list. 214 * 215 * @data: String to parse. 216 * @is_not: True if it is "no_initialize_domain" entry. 217 * @is_delete: True if it is a delete request. 218 * 219 * Returns 0 on success, negative value otherwise. 220 * 221 * Caller holds tomoyo_read_lock(). 222 */ 223int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, 224 const bool is_delete) 225{ 226 char *cp = strstr(data, " from "); 227 228 if (cp) { 229 *cp = '\0'; 230 return tomoyo_update_domain_initializer_entry(cp + 6, data, 231 is_not, 232 is_delete); 233 } 234 return tomoyo_update_domain_initializer_entry(NULL, data, is_not, 235 is_delete); 236} 237 238/** 239 * tomoyo_domain_initializer - Check whether the given program causes domainname reinitialization. 240 * 241 * @domainname: The name of domain. 242 * @program: The name of program. 243 * @last_name: The last component of @domainname. 244 * 245 * Returns true if executing @program reinitializes domain transition, 246 * false otherwise. 247 * 248 * Caller holds tomoyo_read_lock(). 249 */ 250static bool tomoyo_domain_initializer(const struct tomoyo_path_info * 251 domainname, 252 const struct tomoyo_path_info *program, 253 const struct tomoyo_path_info * 254 last_name) 255{ 256 struct tomoyo_domain_initializer_entry *ptr; 257 bool flag = false; 258 259 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 260 [TOMOYO_ID_DOMAIN_INITIALIZER], head.list) { 261 if (ptr->head.is_deleted) 262 continue; 263 if (ptr->domainname) { 264 if (!ptr->is_last_name) { 265 if (ptr->domainname != domainname) 266 continue; 267 } else { 268 if (tomoyo_pathcmp(ptr->domainname, last_name)) 269 continue; 270 } 271 } 272 if (tomoyo_pathcmp(ptr->program, program)) 273 continue; 274 if (ptr->is_not) { 275 flag = false; 276 break; 277 } 278 flag = true; 279 } 280 return flag; 281} 282 283static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a, 284 const struct tomoyo_acl_head *b) 285{ 286 const struct tomoyo_domain_keeper_entry *p1 = 287 container_of(a, typeof(*p1), head); 288 const struct tomoyo_domain_keeper_entry *p2 = 289 container_of(b, typeof(*p2), head); 290 return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name 291 && p1->domainname == p2->domainname 292 && p1->program == p2->program; 293} 294 295/** 296 * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. 297 * 298 * @domainname: The name of domain. 299 * @program: The name of program. May be NULL. 300 * @is_not: True if it is "no_keep_domain" entry. 301 * @is_delete: True if it is a delete request. 302 * 303 * Returns 0 on success, negative value otherwise. 304 * 305 * Caller holds tomoyo_read_lock(). 306 */ 307static int tomoyo_update_domain_keeper_entry(const char *domainname, 308 const char *program, 309 const bool is_not, 310 const bool is_delete) 311{ 312 struct tomoyo_domain_keeper_entry e = { .is_not = is_not }; 313 int error = is_delete ? -ENOENT : -ENOMEM; 314 315 if (!tomoyo_domain_def(domainname) && 316 tomoyo_correct_path(domainname)) 317 e.is_last_name = true; 318 else if (!tomoyo_correct_domain(domainname)) 319 return -EINVAL; 320 if (program) { 321 if (!tomoyo_correct_path(program)) 322 return -EINVAL; 323 e.program = tomoyo_get_name(program); 324 if (!e.program) 325 goto out; 326 } 327 e.domainname = tomoyo_get_name(domainname); 328 if (!e.domainname) 329 goto out; 330 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 331 &tomoyo_policy_list 332 [TOMOYO_ID_DOMAIN_KEEPER], 333 tomoyo_same_domain_keeper_entry); 334 out: 335 tomoyo_put_name(e.domainname); 336 tomoyo_put_name(e.program); 337 return error; 338} 339 340/** 341 * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list. 342 * 343 * @data: String to parse. 344 * @is_not: True if it is "no_keep_domain" entry. 345 * @is_delete: True if it is a delete request. 346 * 347 * Caller holds tomoyo_read_lock(). 348 */ 349int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, 350 const bool is_delete) 351{ 352 char *cp = strstr(data, " from "); 353 354 if (cp) { 355 *cp = '\0'; 356 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not, 357 is_delete); 358 } 359 return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete); 360} 361 362/** 363 * tomoyo_domain_keeper - Check whether the given program causes domain transition suppression. 364 * 365 * @domainname: The name of domain. 366 * @program: The name of program. 367 * @last_name: The last component of @domainname. 368 * 369 * Returns true if executing @program supresses domain transition, 370 * false otherwise. 371 * 372 * Caller holds tomoyo_read_lock(). 373 */ 374static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname, 375 const struct tomoyo_path_info *program, 376 const struct tomoyo_path_info *last_name) 377{ 378 struct tomoyo_domain_keeper_entry *ptr; 379 bool flag = false; 380 381 list_for_each_entry_rcu(ptr, 382 &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER], 383 head.list) { 384 if (ptr->head.is_deleted) 385 continue; 386 if (!ptr->is_last_name) { 387 if (ptr->domainname != domainname) 388 continue; 389 } else { 390 if (tomoyo_pathcmp(ptr->domainname, last_name)) 391 continue; 392 } 393 if (ptr->program && tomoyo_pathcmp(ptr->program, program)) 394 continue; 395 if (ptr->is_not) { 396 flag = false; 397 break; 398 } 399 flag = true; 400 } 401 return flag; 402} 403 404static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, 405 const struct tomoyo_acl_head *b) 406{ 407 const struct tomoyo_aggregator_entry *p1 = container_of(a, typeof(*p1), 408 head); 409 const struct tomoyo_aggregator_entry *p2 = container_of(b, typeof(*p2), 410 head); 411 return p1->original_name == p2->original_name && 412 p1->aggregated_name == p2->aggregated_name; 413} 414 415/** 416 * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator_entry" list. 417 * 418 * @original_name: The original program's name. 419 * @aggregated_name: The program name to use. 420 * @is_delete: True if it is a delete request. 421 * 422 * Returns 0 on success, negative value otherwise. 423 * 424 * Caller holds tomoyo_read_lock(). 425 */ 426static int tomoyo_update_aggregator_entry(const char *original_name, 427 const char *aggregated_name, 428 const bool is_delete) 429{ 430 struct tomoyo_aggregator_entry e = { }; 431 int error = is_delete ? -ENOENT : -ENOMEM; 432 433 if (!tomoyo_correct_path(original_name) || 434 !tomoyo_correct_path(aggregated_name)) 435 return -EINVAL; 436 e.original_name = tomoyo_get_name(original_name); 437 e.aggregated_name = tomoyo_get_name(aggregated_name); 438 if (!e.original_name || !e.aggregated_name || 439 e.aggregated_name->is_patterned) /* No patterns allowed. */ 440 goto out; 441 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 442 &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR], 443 tomoyo_same_aggregator_entry); 444 out: 445 tomoyo_put_name(e.original_name); 446 tomoyo_put_name(e.aggregated_name); 447 return error; 448} 449 450/** 451 * tomoyo_write_aggregator_policy - Write "struct tomoyo_aggregator_entry" list. 452 * 453 * @data: String to parse. 454 * @is_delete: True if it is a delete request. 455 * 456 * Returns 0 on success, negative value otherwise. 457 * 458 * Caller holds tomoyo_read_lock(). 459 */ 460int tomoyo_write_aggregator_policy(char *data, const bool is_delete) 461{ 462 char *cp = strchr(data, ' '); 463 464 if (!cp) 465 return -EINVAL; 466 *cp++ = '\0'; 467 return tomoyo_update_aggregator_entry(data, cp, is_delete); 468} 469 470/** 471 * tomoyo_find_or_assign_new_domain - Create a domain. 472 * 473 * @domainname: The name of domain. 474 * @profile: Profile number to assign if the domain was newly created. 475 * 476 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. 477 * 478 * Caller holds tomoyo_read_lock(). 479 */ 480struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * 481 domainname, 482 const u8 profile) 483{ 484 struct tomoyo_domain_info *entry; 485 struct tomoyo_domain_info *domain = NULL; 486 const struct tomoyo_path_info *saved_domainname; 487 bool found = false; 488 489 if (!tomoyo_correct_domain(domainname)) 490 return NULL; 491 saved_domainname = tomoyo_get_name(domainname); 492 if (!saved_domainname) 493 return NULL; 494 entry = kzalloc(sizeof(*entry), GFP_NOFS); 495 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 496 goto out; 497 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 498 if (domain->is_deleted || 499 tomoyo_pathcmp(saved_domainname, domain->domainname)) 500 continue; 501 found = true; 502 break; 503 } 504 if (!found && tomoyo_memory_ok(entry)) { 505 INIT_LIST_HEAD(&entry->acl_info_list); 506 entry->domainname = saved_domainname; 507 saved_domainname = NULL; 508 entry->profile = profile; 509 list_add_tail_rcu(&entry->list, &tomoyo_domain_list); 510 domain = entry; 511 entry = NULL; 512 found = true; 513 } 514 mutex_unlock(&tomoyo_policy_lock); 515 out: 516 tomoyo_put_name(saved_domainname); 517 kfree(entry); 518 return found ? domain : NULL; 519} 520 521/** 522 * tomoyo_find_next_domain - Find a domain. 523 * 524 * @bprm: Pointer to "struct linux_binprm". 525 * 526 * Returns 0 on success, negative value otherwise. 527 * 528 * Caller holds tomoyo_read_lock(). 529 */ 530int tomoyo_find_next_domain(struct linux_binprm *bprm) 531{ 532 struct tomoyo_request_info r; 533 char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); 534 struct tomoyo_domain_info *old_domain = tomoyo_domain(); 535 struct tomoyo_domain_info *domain = NULL; 536 const char *old_domain_name = old_domain->domainname->name; 537 const char *original_name = bprm->filename; 538 u8 mode; 539 bool is_enforce; 540 int retval = -ENOMEM; 541 bool need_kfree = false; 542 struct tomoyo_path_info rn = { }; /* real name */ 543 struct tomoyo_path_info ln; /* last name */ 544 545 ln.name = tomoyo_get_last_name(old_domain); 546 tomoyo_fill_path_info(&ln); 547 mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 548 is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); 549 if (!tmp) 550 goto out; 551 552 retry: 553 if (need_kfree) { 554 kfree(rn.name); 555 need_kfree = false; 556 } 557 /* Get symlink's pathname of program. */ 558 retval = -ENOENT; 559 rn.name = tomoyo_realpath_nofollow(original_name); 560 if (!rn.name) 561 goto out; 562 tomoyo_fill_path_info(&rn); 563 need_kfree = true; 564 565 /* Check 'aggregator' directive. */ 566 { 567 struct tomoyo_aggregator_entry *ptr; 568 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 569 [TOMOYO_ID_AGGREGATOR], head.list) { 570 if (ptr->head.is_deleted || 571 !tomoyo_path_matches_pattern(&rn, 572 ptr->original_name)) 573 continue; 574 kfree(rn.name); 575 need_kfree = false; 576 /* This is OK because it is read only. */ 577 rn = *ptr->aggregated_name; 578 break; 579 } 580 } 581 582 /* Check execute permission. */ 583 retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn); 584 if (retval == TOMOYO_RETRY_REQUEST) 585 goto retry; 586 if (retval < 0) 587 goto out; 588 589 if (tomoyo_domain_initializer(old_domain->domainname, &rn, &ln)) { 590 /* Transit to the child of tomoyo_kernel_domain domain. */ 591 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, 592 TOMOYO_ROOT_NAME " " "%s", rn.name); 593 } else if (old_domain == &tomoyo_kernel_domain && 594 !tomoyo_policy_loaded) { 595 /* 596 * Needn't to transit from kernel domain before starting 597 * /sbin/init. But transit from kernel domain if executing 598 * initializers because they might start before /sbin/init. 599 */ 600 domain = old_domain; 601 } else if (tomoyo_domain_keeper(old_domain->domainname, &rn, &ln)) { 602 /* Keep current domain. */ 603 domain = old_domain; 604 } else { 605 /* Normal domain transition. */ 606 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, 607 "%s %s", old_domain_name, rn.name); 608 } 609 if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) 610 goto done; 611 domain = tomoyo_find_domain(tmp); 612 if (domain) 613 goto done; 614 if (is_enforce) { 615 int error = tomoyo_supervisor(&r, "# wants to create domain\n" 616 "%s\n", tmp); 617 if (error == TOMOYO_RETRY_REQUEST) 618 goto retry; 619 if (error < 0) 620 goto done; 621 } 622 domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile); 623 done: 624 if (domain) 625 goto out; 626 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); 627 if (is_enforce) 628 retval = -EPERM; 629 else 630 old_domain->transition_failed = true; 631 out: 632 if (!domain) 633 domain = old_domain; 634 /* Update reference count on "struct tomoyo_domain_info". */ 635 atomic_inc(&domain->users); 636 bprm->cred->security = domain; 637 if (need_kfree) 638 kfree(rn.name); 639 kfree(tmp); 640 return retval; 641} 642