domain.c revision cb0abe6a5b58499bd4bc1403f4987af9ead0642c
1/* 2 * security/tomoyo/domain.c 3 * 4 * Implementation of the Domain-Based Mandatory Access Control. 5 * 6 * Copyright (C) 2005-2009 NTT DATA CORPORATION 7 * 8 * Version: 2.2.0 2009/04/01 9 * 10 */ 11 12#include "common.h" 13#include <linux/binfmts.h> 14#include <linux/slab.h> 15 16/* Variables definitions.*/ 17 18/* The initial domain. */ 19struct tomoyo_domain_info tomoyo_kernel_domain; 20 21/* 22 * tomoyo_domain_list is used for holding list of domains. 23 * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding 24 * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. 25 * 26 * An entry is added by 27 * 28 * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \ 29 * /sys/kernel/security/tomoyo/domain_policy 30 * 31 * and is deleted by 32 * 33 * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \ 34 * /sys/kernel/security/tomoyo/domain_policy 35 * 36 * and all entries are retrieved by 37 * 38 * # cat /sys/kernel/security/tomoyo/domain_policy 39 * 40 * A domain is added by 41 * 42 * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy 43 * 44 * and is deleted by 45 * 46 * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy 47 * 48 * and all domains are retrieved by 49 * 50 * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy 51 * 52 * Normally, a domainname is monotonically getting longer because a domainname 53 * which the process will belong to if an execve() operation succeeds is 54 * defined as a concatenation of "current domainname" + "pathname passed to 55 * execve()". 56 * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for 57 * exceptions. 58 */ 59LIST_HEAD(tomoyo_domain_list); 60 61/** 62 * tomoyo_get_last_name - Get last component of a domainname. 63 * 64 * @domain: Pointer to "struct tomoyo_domain_info". 65 * 66 * Returns the last component of the domainname. 67 */ 68const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) 69{ 70 const char *cp0 = domain->domainname->name; 71 const char *cp1 = strrchr(cp0, ' '); 72 73 if (cp1) 74 return cp1 + 1; 75 return cp0; 76} 77 78/* 79 * tomoyo_domain_initializer_list is used for holding list of programs which 80 * triggers reinitialization of domainname. Normally, a domainname is 81 * monotonically getting longer. But sometimes, we restart daemon programs. 82 * It would be convenient for us that "a daemon started upon system boot" and 83 * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO 84 * provides a way to shorten domainnames. 85 * 86 * An entry is added by 87 * 88 * # echo 'initialize_domain /usr/sbin/httpd' > \ 89 * /sys/kernel/security/tomoyo/exception_policy 90 * 91 * and is deleted by 92 * 93 * # echo 'delete initialize_domain /usr/sbin/httpd' > \ 94 * /sys/kernel/security/tomoyo/exception_policy 95 * 96 * and all entries are retrieved by 97 * 98 * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy 99 * 100 * In the example above, /usr/sbin/httpd will belong to 101 * "<kernel> /usr/sbin/httpd" domain. 102 * 103 * You may specify a domainname using "from" keyword. 104 * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" 105 * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd" 106 * domain to belong to "<kernel> /usr/sbin/httpd" domain. 107 * 108 * You may add "no_" prefix to "initialize_domain". 109 * "initialize_domain /usr/sbin/httpd" and 110 * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" 111 * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain 112 * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. 113 */ 114LIST_HEAD(tomoyo_domain_initializer_list); 115 116/** 117 * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. 118 * 119 * @domainname: The name of domain. May be NULL. 120 * @program: The name of program. 121 * @is_not: True if it is "no_initialize_domain" entry. 122 * @is_delete: True if it is a delete request. 123 * 124 * Returns 0 on success, negative value otherwise. 125 * 126 * Caller holds tomoyo_read_lock(). 127 */ 128static int tomoyo_update_domain_initializer_entry(const char *domainname, 129 const char *program, 130 const bool is_not, 131 const bool is_delete) 132{ 133 struct tomoyo_domain_initializer_entry *ptr; 134 struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; 135 int error = is_delete ? -ENOENT : -ENOMEM; 136 137 if (!tomoyo_is_correct_path(program, 1, -1, -1)) 138 return -EINVAL; /* No patterns allowed. */ 139 if (domainname) { 140 if (!tomoyo_is_domain_def(domainname) && 141 tomoyo_is_correct_path(domainname, 1, -1, -1)) 142 e.is_last_name = true; 143 else if (!tomoyo_is_correct_domain(domainname)) 144 return -EINVAL; 145 e.domainname = tomoyo_get_name(domainname); 146 if (!e.domainname) 147 goto out; 148 } 149 e.program = tomoyo_get_name(program); 150 if (!e.program) 151 goto out; 152 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 153 goto out; 154 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { 155 if (!tomoyo_is_same_domain_initializer_entry(ptr, &e)) 156 continue; 157 ptr->is_deleted = is_delete; 158 error = 0; 159 break; 160 } 161 if (!is_delete && error) { 162 struct tomoyo_domain_initializer_entry *entry = 163 tomoyo_commit_ok(&e, sizeof(e)); 164 if (entry) { 165 list_add_tail_rcu(&entry->list, 166 &tomoyo_domain_initializer_list); 167 error = 0; 168 } 169 } 170 mutex_unlock(&tomoyo_policy_lock); 171 out: 172 tomoyo_put_name(e.domainname); 173 tomoyo_put_name(e.program); 174 return error; 175} 176 177/** 178 * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list. 179 * 180 * @head: Pointer to "struct tomoyo_io_buffer". 181 * 182 * Returns true on success, false otherwise. 183 * 184 * Caller holds tomoyo_read_lock(). 185 */ 186bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) 187{ 188 struct list_head *pos; 189 bool done = true; 190 191 list_for_each_cookie(pos, head->read_var2, 192 &tomoyo_domain_initializer_list) { 193 const char *no; 194 const char *from = ""; 195 const char *domain = ""; 196 struct tomoyo_domain_initializer_entry *ptr; 197 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry, 198 list); 199 if (ptr->is_deleted) 200 continue; 201 no = ptr->is_not ? "no_" : ""; 202 if (ptr->domainname) { 203 from = " from "; 204 domain = ptr->domainname->name; 205 } 206 done = tomoyo_io_printf(head, 207 "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN 208 "%s%s%s\n", no, ptr->program->name, 209 from, domain); 210 if (!done) 211 break; 212 } 213 return done; 214} 215 216/** 217 * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list. 218 * 219 * @data: String to parse. 220 * @is_not: True if it is "no_initialize_domain" entry. 221 * @is_delete: True if it is a delete request. 222 * 223 * Returns 0 on success, negative value otherwise. 224 * 225 * Caller holds tomoyo_read_lock(). 226 */ 227int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, 228 const bool is_delete) 229{ 230 char *cp = strstr(data, " from "); 231 232 if (cp) { 233 *cp = '\0'; 234 return tomoyo_update_domain_initializer_entry(cp + 6, data, 235 is_not, 236 is_delete); 237 } 238 return tomoyo_update_domain_initializer_entry(NULL, data, is_not, 239 is_delete); 240} 241 242/** 243 * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization. 244 * 245 * @domainname: The name of domain. 246 * @program: The name of program. 247 * @last_name: The last component of @domainname. 248 * 249 * Returns true if executing @program reinitializes domain transition, 250 * false otherwise. 251 * 252 * Caller holds tomoyo_read_lock(). 253 */ 254static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * 255 domainname, 256 const struct tomoyo_path_info *program, 257 const struct tomoyo_path_info * 258 last_name) 259{ 260 struct tomoyo_domain_initializer_entry *ptr; 261 bool flag = false; 262 263 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { 264 if (ptr->is_deleted) 265 continue; 266 if (ptr->domainname) { 267 if (!ptr->is_last_name) { 268 if (ptr->domainname != domainname) 269 continue; 270 } else { 271 if (tomoyo_pathcmp(ptr->domainname, last_name)) 272 continue; 273 } 274 } 275 if (tomoyo_pathcmp(ptr->program, program)) 276 continue; 277 if (ptr->is_not) { 278 flag = false; 279 break; 280 } 281 flag = true; 282 } 283 return flag; 284} 285 286/* 287 * tomoyo_domain_keeper_list is used for holding list of domainnames which 288 * suppresses domain transition. Normally, a domainname is monotonically 289 * getting longer. But sometimes, we want to suppress domain transition. 290 * It would be convenient for us that programs executed from a login session 291 * belong to the same domain. Thus, TOMOYO provides a way to suppress domain 292 * transition. 293 * 294 * An entry is added by 295 * 296 * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ 297 * /sys/kernel/security/tomoyo/exception_policy 298 * 299 * and is deleted by 300 * 301 * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ 302 * /sys/kernel/security/tomoyo/exception_policy 303 * 304 * and all entries are retrieved by 305 * 306 * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy 307 * 308 * In the example above, any process which belongs to 309 * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain, 310 * unless explicitly specified by "initialize_domain" or "no_keep_domain". 311 * 312 * You may specify a program using "from" keyword. 313 * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash" 314 * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash" 315 * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain. 316 * 317 * You may add "no_" prefix to "keep_domain". 318 * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and 319 * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will 320 * cause "/usr/bin/passwd" to belong to 321 * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless 322 * explicitly specified by "initialize_domain". 323 */ 324LIST_HEAD(tomoyo_domain_keeper_list); 325 326/** 327 * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. 328 * 329 * @domainname: The name of domain. 330 * @program: The name of program. May be NULL. 331 * @is_not: True if it is "no_keep_domain" entry. 332 * @is_delete: True if it is a delete request. 333 * 334 * Returns 0 on success, negative value otherwise. 335 * 336 * Caller holds tomoyo_read_lock(). 337 */ 338static int tomoyo_update_domain_keeper_entry(const char *domainname, 339 const char *program, 340 const bool is_not, 341 const bool is_delete) 342{ 343 struct tomoyo_domain_keeper_entry *ptr; 344 struct tomoyo_domain_keeper_entry e = { .is_not = is_not }; 345 int error = is_delete ? -ENOENT : -ENOMEM; 346 347 if (!tomoyo_is_domain_def(domainname) && 348 tomoyo_is_correct_path(domainname, 1, -1, -1)) 349 e.is_last_name = true; 350 else if (!tomoyo_is_correct_domain(domainname)) 351 return -EINVAL; 352 if (program) { 353 if (!tomoyo_is_correct_path(program, 1, -1, -1)) 354 return -EINVAL; 355 e.program = tomoyo_get_name(program); 356 if (!e.program) 357 goto out; 358 } 359 e.domainname = tomoyo_get_name(domainname); 360 if (!e.domainname) 361 goto out; 362 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 363 goto out; 364 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { 365 if (!tomoyo_is_same_domain_keeper_entry(ptr, &e)) 366 continue; 367 ptr->is_deleted = is_delete; 368 error = 0; 369 break; 370 } 371 if (!is_delete && error) { 372 struct tomoyo_domain_keeper_entry *entry = 373 tomoyo_commit_ok(&e, sizeof(e)); 374 if (entry) { 375 list_add_tail_rcu(&entry->list, 376 &tomoyo_domain_keeper_list); 377 error = 0; 378 } 379 } 380 mutex_unlock(&tomoyo_policy_lock); 381 out: 382 tomoyo_put_name(e.domainname); 383 tomoyo_put_name(e.program); 384 return error; 385} 386 387/** 388 * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list. 389 * 390 * @data: String to parse. 391 * @is_not: True if it is "no_keep_domain" entry. 392 * @is_delete: True if it is a delete request. 393 * 394 * Caller holds tomoyo_read_lock(). 395 */ 396int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, 397 const bool is_delete) 398{ 399 char *cp = strstr(data, " from "); 400 401 if (cp) { 402 *cp = '\0'; 403 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not, 404 is_delete); 405 } 406 return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete); 407} 408 409/** 410 * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list. 411 * 412 * @head: Pointer to "struct tomoyo_io_buffer". 413 * 414 * Returns true on success, false otherwise. 415 * 416 * Caller holds tomoyo_read_lock(). 417 */ 418bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) 419{ 420 struct list_head *pos; 421 bool done = true; 422 423 list_for_each_cookie(pos, head->read_var2, 424 &tomoyo_domain_keeper_list) { 425 struct tomoyo_domain_keeper_entry *ptr; 426 const char *no; 427 const char *from = ""; 428 const char *program = ""; 429 430 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list); 431 if (ptr->is_deleted) 432 continue; 433 no = ptr->is_not ? "no_" : ""; 434 if (ptr->program) { 435 from = " from "; 436 program = ptr->program->name; 437 } 438 done = tomoyo_io_printf(head, 439 "%s" TOMOYO_KEYWORD_KEEP_DOMAIN 440 "%s%s%s\n", no, program, from, 441 ptr->domainname->name); 442 if (!done) 443 break; 444 } 445 return done; 446} 447 448/** 449 * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression. 450 * 451 * @domainname: The name of domain. 452 * @program: The name of program. 453 * @last_name: The last component of @domainname. 454 * 455 * Returns true if executing @program supresses domain transition, 456 * false otherwise. 457 * 458 * Caller holds tomoyo_read_lock(). 459 */ 460static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, 461 const struct tomoyo_path_info *program, 462 const struct tomoyo_path_info *last_name) 463{ 464 struct tomoyo_domain_keeper_entry *ptr; 465 bool flag = false; 466 467 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { 468 if (ptr->is_deleted) 469 continue; 470 if (!ptr->is_last_name) { 471 if (ptr->domainname != domainname) 472 continue; 473 } else { 474 if (tomoyo_pathcmp(ptr->domainname, last_name)) 475 continue; 476 } 477 if (ptr->program && tomoyo_pathcmp(ptr->program, program)) 478 continue; 479 if (ptr->is_not) { 480 flag = false; 481 break; 482 } 483 flag = true; 484 } 485 return flag; 486} 487 488/* 489 * tomoyo_alias_list is used for holding list of symlink's pathnames which are 490 * allowed to be passed to an execve() request. Normally, the domainname which 491 * the current process will belong to after execve() succeeds is calculated 492 * using dereferenced pathnames. But some programs behave differently depending 493 * on the name passed to argv[0]. For busybox, calculating domainname using 494 * dereferenced pathnames will cause all programs in the busybox to belong to 495 * the same domain. Thus, TOMOYO provides a way to allow use of symlink's 496 * pathname for checking execve()'s permission and calculating domainname which 497 * the current process will belong to after execve() succeeds. 498 * 499 * An entry is added by 500 * 501 * # echo 'alias /bin/busybox /bin/cat' > \ 502 * /sys/kernel/security/tomoyo/exception_policy 503 * 504 * and is deleted by 505 * 506 * # echo 'delete alias /bin/busybox /bin/cat' > \ 507 * /sys/kernel/security/tomoyo/exception_policy 508 * 509 * and all entries are retrieved by 510 * 511 * # grep ^alias /sys/kernel/security/tomoyo/exception_policy 512 * 513 * In the example above, if /bin/cat is a symlink to /bin/busybox and execution 514 * of /bin/cat is requested, permission is checked for /bin/cat rather than 515 * /bin/busybox and domainname which the current process will belong to after 516 * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . 517 */ 518LIST_HEAD(tomoyo_alias_list); 519 520/** 521 * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. 522 * 523 * @original_name: The original program's real name. 524 * @aliased_name: The symbolic program's symbolic link's name. 525 * @is_delete: True if it is a delete request. 526 * 527 * Returns 0 on success, negative value otherwise. 528 * 529 * Caller holds tomoyo_read_lock(). 530 */ 531static int tomoyo_update_alias_entry(const char *original_name, 532 const char *aliased_name, 533 const bool is_delete) 534{ 535 struct tomoyo_alias_entry *ptr; 536 struct tomoyo_alias_entry e = { }; 537 int error = is_delete ? -ENOENT : -ENOMEM; 538 539 if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || 540 !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) 541 return -EINVAL; /* No patterns allowed. */ 542 e.original_name = tomoyo_get_name(original_name); 543 e.aliased_name = tomoyo_get_name(aliased_name); 544 if (!e.original_name || !e.aliased_name) 545 goto out; 546 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 547 goto out; 548 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 549 if (!tomoyo_is_same_alias_entry(ptr, &e)) 550 continue; 551 ptr->is_deleted = is_delete; 552 error = 0; 553 break; 554 } 555 if (!is_delete && error) { 556 struct tomoyo_alias_entry *entry = 557 tomoyo_commit_ok(&e, sizeof(e)); 558 if (entry) { 559 list_add_tail_rcu(&entry->list, &tomoyo_alias_list); 560 error = 0; 561 } 562 } 563 mutex_unlock(&tomoyo_policy_lock); 564 out: 565 tomoyo_put_name(e.original_name); 566 tomoyo_put_name(e.aliased_name); 567 return error; 568} 569 570/** 571 * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list. 572 * 573 * @head: Pointer to "struct tomoyo_io_buffer". 574 * 575 * Returns true on success, false otherwise. 576 * 577 * Caller holds tomoyo_read_lock(). 578 */ 579bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) 580{ 581 struct list_head *pos; 582 bool done = true; 583 584 list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { 585 struct tomoyo_alias_entry *ptr; 586 587 ptr = list_entry(pos, struct tomoyo_alias_entry, list); 588 if (ptr->is_deleted) 589 continue; 590 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", 591 ptr->original_name->name, 592 ptr->aliased_name->name); 593 if (!done) 594 break; 595 } 596 return done; 597} 598 599/** 600 * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list. 601 * 602 * @data: String to parse. 603 * @is_delete: True if it is a delete request. 604 * 605 * Returns 0 on success, negative value otherwise. 606 * 607 * Caller holds tomoyo_read_lock(). 608 */ 609int tomoyo_write_alias_policy(char *data, const bool is_delete) 610{ 611 char *cp = strchr(data, ' '); 612 613 if (!cp) 614 return -EINVAL; 615 *cp++ = '\0'; 616 return tomoyo_update_alias_entry(data, cp, is_delete); 617} 618 619/** 620 * tomoyo_find_or_assign_new_domain - Create a domain. 621 * 622 * @domainname: The name of domain. 623 * @profile: Profile number to assign if the domain was newly created. 624 * 625 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. 626 * 627 * Caller holds tomoyo_read_lock(). 628 */ 629struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * 630 domainname, 631 const u8 profile) 632{ 633 struct tomoyo_domain_info *entry; 634 struct tomoyo_domain_info *domain = NULL; 635 const struct tomoyo_path_info *saved_domainname; 636 bool found = false; 637 638 if (!tomoyo_is_correct_domain(domainname)) 639 return NULL; 640 saved_domainname = tomoyo_get_name(domainname); 641 if (!saved_domainname) 642 return NULL; 643 entry = kzalloc(sizeof(*entry), GFP_NOFS); 644 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 645 goto out; 646 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 647 if (domain->is_deleted || 648 tomoyo_pathcmp(saved_domainname, domain->domainname)) 649 continue; 650 found = true; 651 break; 652 } 653 if (!found && tomoyo_memory_ok(entry)) { 654 INIT_LIST_HEAD(&entry->acl_info_list); 655 entry->domainname = saved_domainname; 656 saved_domainname = NULL; 657 entry->profile = profile; 658 list_add_tail_rcu(&entry->list, &tomoyo_domain_list); 659 domain = entry; 660 entry = NULL; 661 found = true; 662 } 663 mutex_unlock(&tomoyo_policy_lock); 664 out: 665 tomoyo_put_name(saved_domainname); 666 kfree(entry); 667 return found ? domain : NULL; 668} 669 670/** 671 * tomoyo_find_next_domain - Find a domain. 672 * 673 * @bprm: Pointer to "struct linux_binprm". 674 * 675 * Returns 0 on success, negative value otherwise. 676 * 677 * Caller holds tomoyo_read_lock(). 678 */ 679int tomoyo_find_next_domain(struct linux_binprm *bprm) 680{ 681 /* 682 * This function assumes that the size of buffer returned by 683 * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. 684 */ 685 struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS); 686 struct tomoyo_domain_info *old_domain = tomoyo_domain(); 687 struct tomoyo_domain_info *domain = NULL; 688 const char *old_domain_name = old_domain->domainname->name; 689 const char *original_name = bprm->filename; 690 char *new_domain_name = NULL; 691 char *real_program_name = NULL; 692 char *symlink_program_name = NULL; 693 const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); 694 const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); 695 int retval = -ENOMEM; 696 struct tomoyo_path_info r; /* real name */ 697 struct tomoyo_path_info s; /* symlink name */ 698 struct tomoyo_path_info l; /* last name */ 699 static bool initialized; 700 701 if (!tmp) 702 goto out; 703 704 if (!initialized) { 705 /* 706 * Built-in initializers. This is needed because policies are 707 * not loaded until starting /sbin/init. 708 */ 709 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug", 710 false, false); 711 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe", 712 false, false); 713 initialized = true; 714 } 715 716 /* Get tomoyo_realpath of program. */ 717 retval = -ENOENT; 718 /* I hope tomoyo_realpath() won't fail with -ENOMEM. */ 719 real_program_name = tomoyo_realpath(original_name); 720 if (!real_program_name) 721 goto out; 722 /* Get tomoyo_realpath of symbolic link. */ 723 symlink_program_name = tomoyo_realpath_nofollow(original_name); 724 if (!symlink_program_name) 725 goto out; 726 727 r.name = real_program_name; 728 tomoyo_fill_path_info(&r); 729 s.name = symlink_program_name; 730 tomoyo_fill_path_info(&s); 731 l.name = tomoyo_get_last_name(old_domain); 732 tomoyo_fill_path_info(&l); 733 734 /* Check 'alias' directive. */ 735 if (tomoyo_pathcmp(&r, &s)) { 736 struct tomoyo_alias_entry *ptr; 737 /* Is this program allowed to be called via symbolic links? */ 738 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 739 if (ptr->is_deleted || 740 tomoyo_pathcmp(&r, ptr->original_name) || 741 tomoyo_pathcmp(&s, ptr->aliased_name)) 742 continue; 743 memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); 744 strncpy(real_program_name, ptr->aliased_name->name, 745 TOMOYO_MAX_PATHNAME_LEN - 1); 746 tomoyo_fill_path_info(&r); 747 break; 748 } 749 } 750 751 /* Check execute permission. */ 752 retval = tomoyo_check_exec_perm(old_domain, &r); 753 if (retval < 0) 754 goto out; 755 756 new_domain_name = tmp->buffer; 757 if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) { 758 /* Transit to the child of tomoyo_kernel_domain domain. */ 759 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, 760 TOMOYO_ROOT_NAME " " "%s", real_program_name); 761 } else if (old_domain == &tomoyo_kernel_domain && 762 !tomoyo_policy_loaded) { 763 /* 764 * Needn't to transit from kernel domain before starting 765 * /sbin/init. But transit from kernel domain if executing 766 * initializers because they might start before /sbin/init. 767 */ 768 domain = old_domain; 769 } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) { 770 /* Keep current domain. */ 771 domain = old_domain; 772 } else { 773 /* Normal domain transition. */ 774 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, 775 "%s %s", old_domain_name, real_program_name); 776 } 777 if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) 778 goto done; 779 domain = tomoyo_find_domain(new_domain_name); 780 if (domain) 781 goto done; 782 if (is_enforce) 783 goto done; 784 domain = tomoyo_find_or_assign_new_domain(new_domain_name, 785 old_domain->profile); 786 done: 787 if (domain) 788 goto out; 789 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", 790 new_domain_name); 791 if (is_enforce) 792 retval = -EPERM; 793 else 794 old_domain->transition_failed = true; 795 out: 796 if (!domain) 797 domain = old_domain; 798 /* Update reference count on "struct tomoyo_domain_info". */ 799 atomic_inc(&domain->users); 800 bprm->cred->security = domain; 801 kfree(real_program_name); 802 kfree(symlink_program_name); 803 kfree(tmp); 804 return retval; 805} 806