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