domain.c revision 57c2590fb7fd38bd52708ff2716a577d0c2b3c5a
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)) 135 return -EINVAL; 136 if (domainname) { 137 if (!tomoyo_is_domain_def(domainname) && 138 tomoyo_is_correct_path(domainname)) 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)) 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)) 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_aggregator_list is used for holding list of rewrite table for 487 * execve() request. Some programs provides similar functionality. This keyword 488 * allows users to aggregate such programs. 489 * 490 * Entries are added by 491 * 492 * # echo 'aggregator /usr/bin/vi /./editor' > \ 493 * /sys/kernel/security/tomoyo/exception_policy 494 * # echo 'aggregator /usr/bin/emacs /./editor' > \ 495 * /sys/kernel/security/tomoyo/exception_policy 496 * 497 * and are deleted by 498 * 499 * # echo 'delete aggregator /usr/bin/vi /./editor' > \ 500 * /sys/kernel/security/tomoyo/exception_policy 501 * # echo 'delete aggregator /usr/bin/emacs /./editor' > \ 502 * /sys/kernel/security/tomoyo/exception_policy 503 * 504 * and all entries are retrieved by 505 * 506 * # grep ^aggregator /sys/kernel/security/tomoyo/exception_policy 507 * 508 * In the example above, if /usr/bin/vi or /usr/bin/emacs are executed, 509 * permission is checked for /./editor and domainname which the current process 510 * will belong to after execve() succeeds is calculated using /./editor . 511 */ 512LIST_HEAD(tomoyo_aggregator_list); 513 514/** 515 * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator_entry" list. 516 * 517 * @original_name: The original program's name. 518 * @aggregated_name: The program name to use. 519 * @is_delete: True if it is a delete request. 520 * 521 * Returns 0 on success, negative value otherwise. 522 * 523 * Caller holds tomoyo_read_lock(). 524 */ 525static int tomoyo_update_aggregator_entry(const char *original_name, 526 const char *aggregated_name, 527 const bool is_delete) 528{ 529 struct tomoyo_aggregator_entry *ptr; 530 struct tomoyo_aggregator_entry e = { }; 531 int error = is_delete ? -ENOENT : -ENOMEM; 532 533 if (!tomoyo_is_correct_path(original_name) || 534 !tomoyo_is_correct_path(aggregated_name)) 535 return -EINVAL; 536 e.original_name = tomoyo_get_name(original_name); 537 e.aggregated_name = tomoyo_get_name(aggregated_name); 538 if (!e.original_name || !e.aggregated_name || 539 e.aggregated_name->is_patterned) /* No patterns allowed. */ 540 goto out; 541 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 542 goto out; 543 list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) { 544 if (!tomoyo_is_same_aggregator_entry(ptr, &e)) 545 continue; 546 ptr->is_deleted = is_delete; 547 error = 0; 548 break; 549 } 550 if (!is_delete && error) { 551 struct tomoyo_aggregator_entry *entry = 552 tomoyo_commit_ok(&e, sizeof(e)); 553 if (entry) { 554 list_add_tail_rcu(&entry->list, 555 &tomoyo_aggregator_list); 556 error = 0; 557 } 558 } 559 mutex_unlock(&tomoyo_policy_lock); 560 out: 561 tomoyo_put_name(e.original_name); 562 tomoyo_put_name(e.aggregated_name); 563 return error; 564} 565 566/** 567 * tomoyo_read_aggregator_policy - Read "struct tomoyo_aggregator_entry" list. 568 * 569 * @head: Pointer to "struct tomoyo_io_buffer". 570 * 571 * Returns true on success, false otherwise. 572 * 573 * Caller holds tomoyo_read_lock(). 574 */ 575bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head) 576{ 577 struct list_head *pos; 578 bool done = true; 579 580 list_for_each_cookie(pos, head->read_var2, &tomoyo_aggregator_list) { 581 struct tomoyo_aggregator_entry *ptr; 582 583 ptr = list_entry(pos, struct tomoyo_aggregator_entry, list); 584 if (ptr->is_deleted) 585 continue; 586 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_AGGREGATOR 587 "%s %s\n", ptr->original_name->name, 588 ptr->aggregated_name->name); 589 if (!done) 590 break; 591 } 592 return done; 593} 594 595/** 596 * tomoyo_write_aggregator_policy - Write "struct tomoyo_aggregator_entry" list. 597 * 598 * @data: String to parse. 599 * @is_delete: True if it is a delete request. 600 * 601 * Returns 0 on success, negative value otherwise. 602 * 603 * Caller holds tomoyo_read_lock(). 604 */ 605int tomoyo_write_aggregator_policy(char *data, const bool is_delete) 606{ 607 char *cp = strchr(data, ' '); 608 609 if (!cp) 610 return -EINVAL; 611 *cp++ = '\0'; 612 return tomoyo_update_aggregator_entry(data, cp, is_delete); 613} 614 615/* 616 * tomoyo_alias_list is used for holding list of symlink's pathnames which are 617 * allowed to be passed to an execve() request. Normally, the domainname which 618 * the current process will belong to after execve() succeeds is calculated 619 * using dereferenced pathnames. But some programs behave differently depending 620 * on the name passed to argv[0]. For busybox, calculating domainname using 621 * dereferenced pathnames will cause all programs in the busybox to belong to 622 * the same domain. Thus, TOMOYO provides a way to allow use of symlink's 623 * pathname for checking execve()'s permission and calculating domainname which 624 * the current process will belong to after execve() succeeds. 625 * 626 * An entry is added by 627 * 628 * # echo 'alias /bin/busybox /bin/cat' > \ 629 * /sys/kernel/security/tomoyo/exception_policy 630 * 631 * and is deleted by 632 * 633 * # echo 'delete alias /bin/busybox /bin/cat' > \ 634 * /sys/kernel/security/tomoyo/exception_policy 635 * 636 * and all entries are retrieved by 637 * 638 * # grep ^alias /sys/kernel/security/tomoyo/exception_policy 639 * 640 * In the example above, if /bin/cat is a symlink to /bin/busybox and execution 641 * of /bin/cat is requested, permission is checked for /bin/cat rather than 642 * /bin/busybox and domainname which the current process will belong to after 643 * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . 644 */ 645LIST_HEAD(tomoyo_alias_list); 646 647/** 648 * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. 649 * 650 * @original_name: The original program's real name. 651 * @aliased_name: The symbolic program's symbolic link's name. 652 * @is_delete: True if it is a delete request. 653 * 654 * Returns 0 on success, negative value otherwise. 655 * 656 * Caller holds tomoyo_read_lock(). 657 */ 658static int tomoyo_update_alias_entry(const char *original_name, 659 const char *aliased_name, 660 const bool is_delete) 661{ 662 struct tomoyo_alias_entry *ptr; 663 struct tomoyo_alias_entry e = { }; 664 int error = is_delete ? -ENOENT : -ENOMEM; 665 666 if (!tomoyo_is_correct_path(original_name) || 667 !tomoyo_is_correct_path(aliased_name)) 668 return -EINVAL; 669 e.original_name = tomoyo_get_name(original_name); 670 e.aliased_name = tomoyo_get_name(aliased_name); 671 if (!e.original_name || !e.aliased_name || 672 e.original_name->is_patterned || e.aliased_name->is_patterned) 673 goto out; /* No patterns allowed. */ 674 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 675 goto out; 676 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 677 if (!tomoyo_is_same_alias_entry(ptr, &e)) 678 continue; 679 ptr->is_deleted = is_delete; 680 error = 0; 681 break; 682 } 683 if (!is_delete && error) { 684 struct tomoyo_alias_entry *entry = 685 tomoyo_commit_ok(&e, sizeof(e)); 686 if (entry) { 687 list_add_tail_rcu(&entry->list, &tomoyo_alias_list); 688 error = 0; 689 } 690 } 691 mutex_unlock(&tomoyo_policy_lock); 692 out: 693 tomoyo_put_name(e.original_name); 694 tomoyo_put_name(e.aliased_name); 695 return error; 696} 697 698/** 699 * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list. 700 * 701 * @head: Pointer to "struct tomoyo_io_buffer". 702 * 703 * Returns true on success, false otherwise. 704 * 705 * Caller holds tomoyo_read_lock(). 706 */ 707bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) 708{ 709 struct list_head *pos; 710 bool done = true; 711 712 list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { 713 struct tomoyo_alias_entry *ptr; 714 715 ptr = list_entry(pos, struct tomoyo_alias_entry, list); 716 if (ptr->is_deleted) 717 continue; 718 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", 719 ptr->original_name->name, 720 ptr->aliased_name->name); 721 if (!done) 722 break; 723 } 724 return done; 725} 726 727/** 728 * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list. 729 * 730 * @data: String to parse. 731 * @is_delete: True if it is a delete request. 732 * 733 * Returns 0 on success, negative value otherwise. 734 * 735 * Caller holds tomoyo_read_lock(). 736 */ 737int tomoyo_write_alias_policy(char *data, const bool is_delete) 738{ 739 char *cp = strchr(data, ' '); 740 741 if (!cp) 742 return -EINVAL; 743 *cp++ = '\0'; 744 return tomoyo_update_alias_entry(data, cp, is_delete); 745} 746 747/** 748 * tomoyo_find_or_assign_new_domain - Create a domain. 749 * 750 * @domainname: The name of domain. 751 * @profile: Profile number to assign if the domain was newly created. 752 * 753 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. 754 * 755 * Caller holds tomoyo_read_lock(). 756 */ 757struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * 758 domainname, 759 const u8 profile) 760{ 761 struct tomoyo_domain_info *entry; 762 struct tomoyo_domain_info *domain = NULL; 763 const struct tomoyo_path_info *saved_domainname; 764 bool found = false; 765 766 if (!tomoyo_is_correct_domain(domainname)) 767 return NULL; 768 saved_domainname = tomoyo_get_name(domainname); 769 if (!saved_domainname) 770 return NULL; 771 entry = kzalloc(sizeof(*entry), GFP_NOFS); 772 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 773 goto out; 774 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 775 if (domain->is_deleted || 776 tomoyo_pathcmp(saved_domainname, domain->domainname)) 777 continue; 778 found = true; 779 break; 780 } 781 if (!found && tomoyo_memory_ok(entry)) { 782 INIT_LIST_HEAD(&entry->acl_info_list); 783 entry->domainname = saved_domainname; 784 saved_domainname = NULL; 785 entry->profile = profile; 786 list_add_tail_rcu(&entry->list, &tomoyo_domain_list); 787 domain = entry; 788 entry = NULL; 789 found = true; 790 } 791 mutex_unlock(&tomoyo_policy_lock); 792 out: 793 tomoyo_put_name(saved_domainname); 794 kfree(entry); 795 return found ? domain : NULL; 796} 797 798/** 799 * tomoyo_find_next_domain - Find a domain. 800 * 801 * @bprm: Pointer to "struct linux_binprm". 802 * 803 * Returns 0 on success, negative value otherwise. 804 * 805 * Caller holds tomoyo_read_lock(). 806 */ 807int tomoyo_find_next_domain(struct linux_binprm *bprm) 808{ 809 struct tomoyo_request_info r; 810 char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); 811 struct tomoyo_domain_info *old_domain = tomoyo_domain(); 812 struct tomoyo_domain_info *domain = NULL; 813 const char *old_domain_name = old_domain->domainname->name; 814 const char *original_name = bprm->filename; 815 u8 mode; 816 bool is_enforce; 817 int retval = -ENOMEM; 818 bool need_kfree = false; 819 struct tomoyo_path_info rn = { }; /* real name */ 820 struct tomoyo_path_info sn = { }; /* symlink name */ 821 struct tomoyo_path_info ln; /* last name */ 822 823 ln.name = tomoyo_get_last_name(old_domain); 824 tomoyo_fill_path_info(&ln); 825 mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 826 is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); 827 if (!tmp) 828 goto out; 829 830 retry: 831 if (need_kfree) { 832 kfree(rn.name); 833 need_kfree = false; 834 } 835 /* Get tomoyo_realpath of program. */ 836 retval = -ENOENT; 837 rn.name = tomoyo_realpath(original_name); 838 if (!rn.name) 839 goto out; 840 tomoyo_fill_path_info(&rn); 841 need_kfree = true; 842 843 /* Get tomoyo_realpath of symbolic link. */ 844 sn.name = tomoyo_realpath_nofollow(original_name); 845 if (!sn.name) 846 goto out; 847 tomoyo_fill_path_info(&sn); 848 849 /* Check 'alias' directive. */ 850 if (tomoyo_pathcmp(&rn, &sn)) { 851 struct tomoyo_alias_entry *ptr; 852 /* Is this program allowed to be called via symbolic links? */ 853 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { 854 if (ptr->is_deleted || 855 tomoyo_pathcmp(&rn, ptr->original_name) || 856 tomoyo_pathcmp(&sn, ptr->aliased_name)) 857 continue; 858 kfree(rn.name); 859 need_kfree = false; 860 /* This is OK because it is read only. */ 861 rn = *ptr->aliased_name; 862 break; 863 } 864 } 865 866 /* Check 'aggregator' directive. */ 867 { 868 struct tomoyo_aggregator_entry *ptr; 869 list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) { 870 if (ptr->is_deleted || 871 !tomoyo_path_matches_pattern(&rn, 872 ptr->original_name)) 873 continue; 874 if (need_kfree) 875 kfree(rn.name); 876 need_kfree = false; 877 /* This is OK because it is read only. */ 878 rn = *ptr->aggregated_name; 879 break; 880 } 881 } 882 883 /* Check execute permission. */ 884 retval = tomoyo_check_exec_perm(&r, &rn); 885 if (retval == TOMOYO_RETRY_REQUEST) 886 goto retry; 887 if (retval < 0) 888 goto out; 889 890 if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) { 891 /* Transit to the child of tomoyo_kernel_domain domain. */ 892 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, 893 TOMOYO_ROOT_NAME " " "%s", rn.name); 894 } else if (old_domain == &tomoyo_kernel_domain && 895 !tomoyo_policy_loaded) { 896 /* 897 * Needn't to transit from kernel domain before starting 898 * /sbin/init. But transit from kernel domain if executing 899 * initializers because they might start before /sbin/init. 900 */ 901 domain = old_domain; 902 } else if (tomoyo_is_domain_keeper(old_domain->domainname, &rn, &ln)) { 903 /* Keep current domain. */ 904 domain = old_domain; 905 } else { 906 /* Normal domain transition. */ 907 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, 908 "%s %s", old_domain_name, rn.name); 909 } 910 if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) 911 goto done; 912 domain = tomoyo_find_domain(tmp); 913 if (domain) 914 goto done; 915 if (is_enforce) { 916 int error = tomoyo_supervisor(&r, "# wants to create domain\n" 917 "%s\n", tmp); 918 if (error == TOMOYO_RETRY_REQUEST) 919 goto retry; 920 if (error < 0) 921 goto done; 922 } 923 domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile); 924 done: 925 if (domain) 926 goto out; 927 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); 928 if (is_enforce) 929 retval = -EPERM; 930 else 931 old_domain->transition_failed = true; 932 out: 933 if (!domain) 934 domain = old_domain; 935 /* Update reference count on "struct tomoyo_domain_info". */ 936 atomic_inc(&domain->users); 937 bprm->cred->security = domain; 938 if (need_kfree) 939 kfree(rn.name); 940 kfree(sn.name); 941 kfree(tmp); 942 return retval; 943} 944