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