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