diff options
Diffstat (limited to 'security/tomoyo/domain.c')
-rw-r--r-- | security/tomoyo/domain.c | 219 |
1 files changed, 27 insertions, 192 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 1a122974240f..3575b0e7c7fd 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -127,46 +127,12 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, | |||
127 | r->granted = false; | 127 | r->granted = false; |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | 130 | /* The list for "struct tomoyo_domain_info". */ |
131 | * tomoyo_domain_list is used for holding list of domains. | ||
132 | * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding | ||
133 | * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
134 | * | ||
135 | * An entry is added by | ||
136 | * | ||
137 | * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \ | ||
138 | * /sys/kernel/security/tomoyo/domain_policy | ||
139 | * | ||
140 | * and is deleted by | ||
141 | * | ||
142 | * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \ | ||
143 | * /sys/kernel/security/tomoyo/domain_policy | ||
144 | * | ||
145 | * and all entries are retrieved by | ||
146 | * | ||
147 | * # cat /sys/kernel/security/tomoyo/domain_policy | ||
148 | * | ||
149 | * A domain is added by | ||
150 | * | ||
151 | * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
152 | * | ||
153 | * and is deleted by | ||
154 | * | ||
155 | * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
156 | * | ||
157 | * and all domains are retrieved by | ||
158 | * | ||
159 | * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | ||
160 | * | ||
161 | * Normally, a domainname is monotonically getting longer because a domainname | ||
162 | * which the process will belong to if an execve() operation succeeds is | ||
163 | * defined as a concatenation of "current domainname" + "pathname passed to | ||
164 | * execve()". | ||
165 | * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for | ||
166 | * exceptions. | ||
167 | */ | ||
168 | LIST_HEAD(tomoyo_domain_list); | 131 | LIST_HEAD(tomoyo_domain_list); |
169 | 132 | ||
133 | struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; | ||
134 | struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; | ||
135 | |||
170 | /** | 136 | /** |
171 | * tomoyo_get_last_name - Get last component of a domainname. | 137 | * tomoyo_get_last_name - Get last component of a domainname. |
172 | * | 138 | * |
@@ -184,44 +150,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
184 | return cp0; | 150 | return cp0; |
185 | } | 151 | } |
186 | 152 | ||
187 | /* | ||
188 | * tomoyo_domain_initializer_list is used for holding list of programs which | ||
189 | * triggers reinitialization of domainname. Normally, a domainname is | ||
190 | * monotonically getting longer. But sometimes, we restart daemon programs. | ||
191 | * It would be convenient for us that "a daemon started upon system boot" and | ||
192 | * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO | ||
193 | * provides a way to shorten domainnames. | ||
194 | * | ||
195 | * An entry is added by | ||
196 | * | ||
197 | * # echo 'initialize_domain /usr/sbin/httpd' > \ | ||
198 | * /sys/kernel/security/tomoyo/exception_policy | ||
199 | * | ||
200 | * and is deleted by | ||
201 | * | ||
202 | * # echo 'delete initialize_domain /usr/sbin/httpd' > \ | ||
203 | * /sys/kernel/security/tomoyo/exception_policy | ||
204 | * | ||
205 | * and all entries are retrieved by | ||
206 | * | ||
207 | * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy | ||
208 | * | ||
209 | * In the example above, /usr/sbin/httpd will belong to | ||
210 | * "<kernel> /usr/sbin/httpd" domain. | ||
211 | * | ||
212 | * You may specify a domainname using "from" keyword. | ||
213 | * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
214 | * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd" | ||
215 | * domain to belong to "<kernel> /usr/sbin/httpd" domain. | ||
216 | * | ||
217 | * You may add "no_" prefix to "initialize_domain". | ||
218 | * "initialize_domain /usr/sbin/httpd" and | ||
219 | * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
220 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | ||
221 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | ||
222 | */ | ||
223 | LIST_HEAD(tomoyo_domain_initializer_list); | ||
224 | |||
225 | static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head * | 153 | static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head * |
226 | a, | 154 | a, |
227 | const struct tomoyo_acl_head * | 155 | const struct tomoyo_acl_head * |
@@ -272,7 +200,8 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
272 | if (!e.program) | 200 | if (!e.program) |
273 | goto out; | 201 | goto out; |
274 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 202 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
275 | &tomoyo_domain_initializer_list, | 203 | &tomoyo_policy_list |
204 | [TOMOYO_ID_DOMAIN_INITIALIZER], | ||
276 | tomoyo_same_domain_initializer_entry); | 205 | tomoyo_same_domain_initializer_entry); |
277 | out: | 206 | out: |
278 | tomoyo_put_name(e.domainname); | 207 | tomoyo_put_name(e.domainname); |
@@ -294,8 +223,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
294 | struct list_head *pos; | 223 | struct list_head *pos; |
295 | bool done = true; | 224 | bool done = true; |
296 | 225 | ||
297 | list_for_each_cookie(pos, head->read_var2, | 226 | list_for_each_cookie(pos, head->read_var2, &tomoyo_policy_list |
298 | &tomoyo_domain_initializer_list) { | 227 | [TOMOYO_ID_DOMAIN_INITIALIZER]) { |
299 | const char *no; | 228 | const char *no; |
300 | const char *from = ""; | 229 | const char *from = ""; |
301 | const char *domain = ""; | 230 | const char *domain = ""; |
@@ -366,8 +295,8 @@ static bool tomoyo_domain_initializer(const struct tomoyo_path_info * | |||
366 | struct tomoyo_domain_initializer_entry *ptr; | 295 | struct tomoyo_domain_initializer_entry *ptr; |
367 | bool flag = false; | 296 | bool flag = false; |
368 | 297 | ||
369 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, | 298 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list |
370 | head.list) { | 299 | [TOMOYO_ID_DOMAIN_INITIALIZER], head.list) { |
371 | if (ptr->head.is_deleted) | 300 | if (ptr->head.is_deleted) |
372 | continue; | 301 | continue; |
373 | if (ptr->domainname) { | 302 | if (ptr->domainname) { |
@@ -390,46 +319,6 @@ static bool tomoyo_domain_initializer(const struct tomoyo_path_info * | |||
390 | return flag; | 319 | return flag; |
391 | } | 320 | } |
392 | 321 | ||
393 | /* | ||
394 | * tomoyo_domain_keeper_list is used for holding list of domainnames which | ||
395 | * suppresses domain transition. Normally, a domainname is monotonically | ||
396 | * getting longer. But sometimes, we want to suppress domain transition. | ||
397 | * It would be convenient for us that programs executed from a login session | ||
398 | * belong to the same domain. Thus, TOMOYO provides a way to suppress domain | ||
399 | * transition. | ||
400 | * | ||
401 | * An entry is added by | ||
402 | * | ||
403 | * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
404 | * /sys/kernel/security/tomoyo/exception_policy | ||
405 | * | ||
406 | * and is deleted by | ||
407 | * | ||
408 | * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
409 | * /sys/kernel/security/tomoyo/exception_policy | ||
410 | * | ||
411 | * and all entries are retrieved by | ||
412 | * | ||
413 | * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy | ||
414 | * | ||
415 | * In the example above, any process which belongs to | ||
416 | * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain, | ||
417 | * unless explicitly specified by "initialize_domain" or "no_keep_domain". | ||
418 | * | ||
419 | * You may specify a program using "from" keyword. | ||
420 | * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash" | ||
421 | * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash" | ||
422 | * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain. | ||
423 | * | ||
424 | * You may add "no_" prefix to "keep_domain". | ||
425 | * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and | ||
426 | * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will | ||
427 | * cause "/usr/bin/passwd" to belong to | ||
428 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | ||
429 | * explicitly specified by "initialize_domain". | ||
430 | */ | ||
431 | LIST_HEAD(tomoyo_domain_keeper_list); | ||
432 | |||
433 | static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a, | 322 | static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a, |
434 | const struct tomoyo_acl_head *b) | 323 | const struct tomoyo_acl_head *b) |
435 | { | 324 | { |
@@ -478,7 +367,8 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
478 | if (!e.domainname) | 367 | if (!e.domainname) |
479 | goto out; | 368 | goto out; |
480 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 369 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
481 | &tomoyo_domain_keeper_list, | 370 | &tomoyo_policy_list |
371 | [TOMOYO_ID_DOMAIN_KEEPER], | ||
482 | tomoyo_same_domain_keeper_entry); | 372 | tomoyo_same_domain_keeper_entry); |
483 | out: | 373 | out: |
484 | tomoyo_put_name(e.domainname); | 374 | tomoyo_put_name(e.domainname); |
@@ -523,7 +413,7 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
523 | bool done = true; | 413 | bool done = true; |
524 | 414 | ||
525 | list_for_each_cookie(pos, head->read_var2, | 415 | list_for_each_cookie(pos, head->read_var2, |
526 | &tomoyo_domain_keeper_list) { | 416 | &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER]) { |
527 | struct tomoyo_domain_keeper_entry *ptr; | 417 | struct tomoyo_domain_keeper_entry *ptr; |
528 | const char *no; | 418 | const char *no; |
529 | const char *from = ""; | 419 | const char *from = ""; |
@@ -567,7 +457,9 @@ static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname, | |||
567 | struct tomoyo_domain_keeper_entry *ptr; | 457 | struct tomoyo_domain_keeper_entry *ptr; |
568 | bool flag = false; | 458 | bool flag = false; |
569 | 459 | ||
570 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, head.list) { | 460 | list_for_each_entry_rcu(ptr, |
461 | &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER], | ||
462 | head.list) { | ||
571 | if (ptr->head.is_deleted) | 463 | if (ptr->head.is_deleted) |
572 | continue; | 464 | continue; |
573 | if (!ptr->is_last_name) { | 465 | if (!ptr->is_last_name) { |
@@ -588,35 +480,6 @@ static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname, | |||
588 | return flag; | 480 | return flag; |
589 | } | 481 | } |
590 | 482 | ||
591 | /* | ||
592 | * tomoyo_aggregator_list is used for holding list of rewrite table for | ||
593 | * execve() request. Some programs provides similar functionality. This keyword | ||
594 | * allows users to aggregate such programs. | ||
595 | * | ||
596 | * Entries are added by | ||
597 | * | ||
598 | * # echo 'aggregator /usr/bin/vi /./editor' > \ | ||
599 | * /sys/kernel/security/tomoyo/exception_policy | ||
600 | * # echo 'aggregator /usr/bin/emacs /./editor' > \ | ||
601 | * /sys/kernel/security/tomoyo/exception_policy | ||
602 | * | ||
603 | * and are deleted by | ||
604 | * | ||
605 | * # echo 'delete aggregator /usr/bin/vi /./editor' > \ | ||
606 | * /sys/kernel/security/tomoyo/exception_policy | ||
607 | * # echo 'delete aggregator /usr/bin/emacs /./editor' > \ | ||
608 | * /sys/kernel/security/tomoyo/exception_policy | ||
609 | * | ||
610 | * and all entries are retrieved by | ||
611 | * | ||
612 | * # grep ^aggregator /sys/kernel/security/tomoyo/exception_policy | ||
613 | * | ||
614 | * In the example above, if /usr/bin/vi or /usr/bin/emacs are executed, | ||
615 | * permission is checked for /./editor and domainname which the current process | ||
616 | * will belong to after execve() succeeds is calculated using /./editor . | ||
617 | */ | ||
618 | LIST_HEAD(tomoyo_aggregator_list); | ||
619 | |||
620 | static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, | 483 | static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, |
621 | const struct tomoyo_acl_head *b) | 484 | const struct tomoyo_acl_head *b) |
622 | { | 485 | { |
@@ -655,7 +518,7 @@ static int tomoyo_update_aggregator_entry(const char *original_name, | |||
655 | e.aggregated_name->is_patterned) /* No patterns allowed. */ | 518 | e.aggregated_name->is_patterned) /* No patterns allowed. */ |
656 | goto out; | 519 | goto out; |
657 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 520 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
658 | &tomoyo_aggregator_list, | 521 | &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR], |
659 | tomoyo_same_aggregator_entry); | 522 | tomoyo_same_aggregator_entry); |
660 | out: | 523 | out: |
661 | tomoyo_put_name(e.original_name); | 524 | tomoyo_put_name(e.original_name); |
@@ -677,7 +540,8 @@ bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head) | |||
677 | struct list_head *pos; | 540 | struct list_head *pos; |
678 | bool done = true; | 541 | bool done = true; |
679 | 542 | ||
680 | list_for_each_cookie(pos, head->read_var2, &tomoyo_aggregator_list) { | 543 | list_for_each_cookie(pos, head->read_var2, |
544 | &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]) { | ||
681 | struct tomoyo_aggregator_entry *ptr; | 545 | struct tomoyo_aggregator_entry *ptr; |
682 | 546 | ||
683 | ptr = list_entry(pos, struct tomoyo_aggregator_entry, | 547 | ptr = list_entry(pos, struct tomoyo_aggregator_entry, |
@@ -713,38 +577,6 @@ int tomoyo_write_aggregator_policy(char *data, const bool is_delete) | |||
713 | return tomoyo_update_aggregator_entry(data, cp, is_delete); | 577 | return tomoyo_update_aggregator_entry(data, cp, is_delete); |
714 | } | 578 | } |
715 | 579 | ||
716 | /* | ||
717 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are | ||
718 | * allowed to be passed to an execve() request. Normally, the domainname which | ||
719 | * the current process will belong to after execve() succeeds is calculated | ||
720 | * using dereferenced pathnames. But some programs behave differently depending | ||
721 | * on the name passed to argv[0]. For busybox, calculating domainname using | ||
722 | * dereferenced pathnames will cause all programs in the busybox to belong to | ||
723 | * the same domain. Thus, TOMOYO provides a way to allow use of symlink's | ||
724 | * pathname for checking execve()'s permission and calculating domainname which | ||
725 | * the current process will belong to after execve() succeeds. | ||
726 | * | ||
727 | * An entry is added by | ||
728 | * | ||
729 | * # echo 'alias /bin/busybox /bin/cat' > \ | ||
730 | * /sys/kernel/security/tomoyo/exception_policy | ||
731 | * | ||
732 | * and is deleted by | ||
733 | * | ||
734 | * # echo 'delete alias /bin/busybox /bin/cat' > \ | ||
735 | * /sys/kernel/security/tomoyo/exception_policy | ||
736 | * | ||
737 | * and all entries are retrieved by | ||
738 | * | ||
739 | * # grep ^alias /sys/kernel/security/tomoyo/exception_policy | ||
740 | * | ||
741 | * In the example above, if /bin/cat is a symlink to /bin/busybox and execution | ||
742 | * of /bin/cat is requested, permission is checked for /bin/cat rather than | ||
743 | * /bin/busybox and domainname which the current process will belong to after | ||
744 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | ||
745 | */ | ||
746 | LIST_HEAD(tomoyo_alias_list); | ||
747 | |||
748 | static bool tomoyo_same_alias_entry(const struct tomoyo_acl_head *a, | 580 | static bool tomoyo_same_alias_entry(const struct tomoyo_acl_head *a, |
749 | const struct tomoyo_acl_head *b) | 581 | const struct tomoyo_acl_head *b) |
750 | { | 582 | { |
@@ -783,7 +615,7 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
783 | e.original_name->is_patterned || e.aliased_name->is_patterned) | 615 | e.original_name->is_patterned || e.aliased_name->is_patterned) |
784 | goto out; /* No patterns allowed. */ | 616 | goto out; /* No patterns allowed. */ |
785 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 617 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
786 | &tomoyo_alias_list, | 618 | &tomoyo_policy_list[TOMOYO_ID_ALIAS], |
787 | tomoyo_same_alias_entry); | 619 | tomoyo_same_alias_entry); |
788 | out: | 620 | out: |
789 | tomoyo_put_name(e.original_name); | 621 | tomoyo_put_name(e.original_name); |
@@ -805,7 +637,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
805 | struct list_head *pos; | 637 | struct list_head *pos; |
806 | bool done = true; | 638 | bool done = true; |
807 | 639 | ||
808 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { | 640 | list_for_each_cookie(pos, head->read_var2, |
641 | &tomoyo_policy_list[TOMOYO_ID_ALIAS]) { | ||
809 | struct tomoyo_alias_entry *ptr; | 642 | struct tomoyo_alias_entry *ptr; |
810 | 643 | ||
811 | ptr = list_entry(pos, struct tomoyo_alias_entry, head.list); | 644 | ptr = list_entry(pos, struct tomoyo_alias_entry, head.list); |
@@ -946,7 +779,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
946 | if (tomoyo_pathcmp(&rn, &sn)) { | 779 | if (tomoyo_pathcmp(&rn, &sn)) { |
947 | struct tomoyo_alias_entry *ptr; | 780 | struct tomoyo_alias_entry *ptr; |
948 | /* Is this program allowed to be called via symbolic links? */ | 781 | /* Is this program allowed to be called via symbolic links? */ |
949 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, head.list) { | 782 | list_for_each_entry_rcu(ptr, |
783 | &tomoyo_policy_list[TOMOYO_ID_ALIAS], | ||
784 | head.list) { | ||
950 | if (ptr->head.is_deleted || | 785 | if (ptr->head.is_deleted || |
951 | tomoyo_pathcmp(&rn, ptr->original_name) || | 786 | tomoyo_pathcmp(&rn, ptr->original_name) || |
952 | tomoyo_pathcmp(&sn, ptr->aliased_name)) | 787 | tomoyo_pathcmp(&sn, ptr->aliased_name)) |
@@ -962,8 +797,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
962 | /* Check 'aggregator' directive. */ | 797 | /* Check 'aggregator' directive. */ |
963 | { | 798 | { |
964 | struct tomoyo_aggregator_entry *ptr; | 799 | struct tomoyo_aggregator_entry *ptr; |
965 | list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, | 800 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list |
966 | head.list) { | 801 | [TOMOYO_ID_AGGREGATOR], head.list) { |
967 | if (ptr->head.is_deleted || | 802 | if (ptr->head.is_deleted || |
968 | !tomoyo_path_matches_pattern(&rn, | 803 | !tomoyo_path_matches_pattern(&rn, |
969 | ptr->original_name)) | 804 | ptr->original_name)) |