diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-06-03 07:38:03 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 01:33:42 -0400 |
commit | 1084307ca097745ed6e40a192329b133a49271ac (patch) | |
tree | f3b2e81705afb4ca3006ebb931aa0aad426ace02 /security/tomoyo | |
parent | 3f629636320dfa65804779a3fc333f3147f3b064 (diff) |
TOMOYO: Add pathname aggregation support.
This patch allows users to aggregate programs which provide similar
functionality (e.g. /usr/bin/vi and /usr/bin/emacs ).
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 4 | ||||
-rw-r--r-- | security/tomoyo/common.h | 32 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 147 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 21 |
4 files changed, 204 insertions, 0 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 3f94011c6411..bdf1ed7ca45b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1141,6 +1141,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
1141 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) | 1141 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) |
1142 | return tomoyo_write_domain_initializer_policy(data, true, | 1142 | return tomoyo_write_domain_initializer_policy(data, true, |
1143 | is_delete); | 1143 | is_delete); |
1144 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR)) | ||
1145 | return tomoyo_write_aggregator_policy(data, is_delete); | ||
1144 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS)) | 1146 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS)) |
1145 | return tomoyo_write_alias_policy(data, is_delete); | 1147 | return tomoyo_write_alias_policy(data, is_delete); |
1146 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) | 1148 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) |
@@ -1196,6 +1198,8 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | |||
1196 | head->read_var2 = NULL; | 1198 | head->read_var2 = NULL; |
1197 | head->read_step = 6; | 1199 | head->read_step = 6; |
1198 | case 6: | 1200 | case 6: |
1201 | if (!tomoyo_read_aggregator_policy(head)) | ||
1202 | break; | ||
1199 | head->read_var2 = NULL; | 1203 | head->read_var2 = NULL; |
1200 | head->read_step = 7; | 1204 | head->read_step = 7; |
1201 | case 7: | 1205 | case 7: |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index d1b8d791bfff..54db39aa339b 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -46,6 +46,7 @@ enum tomoyo_mode_index { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* Keywords for ACLs. */ | 48 | /* Keywords for ACLs. */ |
49 | #define TOMOYO_KEYWORD_AGGREGATOR "aggregator " | ||
49 | #define TOMOYO_KEYWORD_ALIAS "alias " | 50 | #define TOMOYO_KEYWORD_ALIAS "alias " |
50 | #define TOMOYO_KEYWORD_ALLOW_MOUNT "allow_mount " | 51 | #define TOMOYO_KEYWORD_ALLOW_MOUNT "allow_mount " |
51 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | 52 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " |
@@ -593,6 +594,24 @@ struct tomoyo_domain_keeper_entry { | |||
593 | }; | 594 | }; |
594 | 595 | ||
595 | /* | 596 | /* |
597 | * tomoyo_aggregator_entry is a structure which is used for holding | ||
598 | * "aggregator" entries. | ||
599 | * It has following fields. | ||
600 | * | ||
601 | * (1) "list" which is linked to tomoyo_aggregator_list . | ||
602 | * (2) "original_name" which is originally requested name. | ||
603 | * (3) "aggregated_name" which is name to rewrite. | ||
604 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
605 | * otherwise. | ||
606 | */ | ||
607 | struct tomoyo_aggregator_entry { | ||
608 | struct list_head list; | ||
609 | const struct tomoyo_path_info *original_name; | ||
610 | const struct tomoyo_path_info *aggregated_name; | ||
611 | bool is_deleted; | ||
612 | }; | ||
613 | |||
614 | /* | ||
596 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | 615 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. |
597 | * It has following fields. | 616 | * It has following fields. |
598 | * | 617 | * |
@@ -693,6 +712,8 @@ bool tomoyo_print_number_union(struct tomoyo_io_buffer *head, | |||
693 | const struct tomoyo_number_union *ptr); | 712 | const struct tomoyo_number_union *ptr); |
694 | bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num); | 713 | bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num); |
695 | 714 | ||
715 | /* Read "aggregator" entry in exception policy. */ | ||
716 | bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head); | ||
696 | /* Read "alias" entry in exception policy. */ | 717 | /* Read "alias" entry in exception policy. */ |
697 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head); | 718 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head); |
698 | /* | 719 | /* |
@@ -730,6 +751,8 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, | |||
730 | /* Check permission for mount operation. */ | 751 | /* Check permission for mount operation. */ |
731 | int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | 752 | int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, |
732 | unsigned long flags, void *data_page); | 753 | unsigned long flags, void *data_page); |
754 | /* Create "aggregator" entry in exception policy. */ | ||
755 | int tomoyo_write_aggregator_policy(char *data, const bool is_delete); | ||
733 | /* Create "alias" entry in exception policy. */ | 756 | /* Create "alias" entry in exception policy. */ |
734 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 757 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
735 | /* | 758 | /* |
@@ -857,6 +880,7 @@ extern struct list_head tomoyo_path_group_list; | |||
857 | extern struct list_head tomoyo_number_group_list; | 880 | extern struct list_head tomoyo_number_group_list; |
858 | extern struct list_head tomoyo_domain_initializer_list; | 881 | extern struct list_head tomoyo_domain_initializer_list; |
859 | extern struct list_head tomoyo_domain_keeper_list; | 882 | extern struct list_head tomoyo_domain_keeper_list; |
883 | extern struct list_head tomoyo_aggregator_list; | ||
860 | extern struct list_head tomoyo_alias_list; | 884 | extern struct list_head tomoyo_alias_list; |
861 | extern struct list_head tomoyo_globally_readable_list; | 885 | extern struct list_head tomoyo_globally_readable_list; |
862 | extern struct list_head tomoyo_pattern_list; | 886 | extern struct list_head tomoyo_pattern_list; |
@@ -1036,6 +1060,14 @@ static inline bool tomoyo_is_same_domain_keeper_entry | |||
1036 | && p1->program == p2->program; | 1060 | && p1->program == p2->program; |
1037 | } | 1061 | } |
1038 | 1062 | ||
1063 | static inline bool tomoyo_is_same_aggregator_entry | ||
1064 | (const struct tomoyo_aggregator_entry *p1, | ||
1065 | const struct tomoyo_aggregator_entry *p2) | ||
1066 | { | ||
1067 | return p1->original_name == p2->original_name && | ||
1068 | p1->aggregated_name == p2->aggregated_name; | ||
1069 | } | ||
1070 | |||
1039 | static inline bool tomoyo_is_same_alias_entry | 1071 | static inline bool tomoyo_is_same_alias_entry |
1040 | (const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2) | 1072 | (const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2) |
1041 | { | 1073 | { |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 50f6e7972174..a07ca6dc1a08 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -483,6 +483,136 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
483 | } | 483 | } |
484 | 484 | ||
485 | /* | 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 | */ | ||
512 | LIST_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 | */ | ||
525 | static 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 | */ | ||
575 | bool 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 | */ | ||
605 | int 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 | /* | ||
486 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are | 616 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are |
487 | * allowed to be passed to an execve() request. Normally, the domainname which | 617 | * allowed to be passed to an execve() request. Normally, the domainname which |
488 | * the current process will belong to after execve() succeeds is calculated | 618 | * the current process will belong to after execve() succeeds is calculated |
@@ -732,6 +862,23 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
732 | } | 862 | } |
733 | } | 863 | } |
734 | 864 | ||
865 | /* Check 'aggregator' directive. */ | ||
866 | { | ||
867 | struct tomoyo_aggregator_entry *ptr; | ||
868 | list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) { | ||
869 | if (ptr->is_deleted || | ||
870 | !tomoyo_path_matches_pattern(&rn, | ||
871 | ptr->original_name)) | ||
872 | continue; | ||
873 | if (need_kfree) | ||
874 | kfree(rn.name); | ||
875 | need_kfree = false; | ||
876 | /* This is OK because it is read only. */ | ||
877 | rn = *ptr->aggregated_name; | ||
878 | break; | ||
879 | } | ||
880 | } | ||
881 | |||
735 | /* Check execute permission. */ | 882 | /* Check execute permission. */ |
736 | retval = tomoyo_check_exec_perm(old_domain, &rn); | 883 | retval = tomoyo_check_exec_perm(old_domain, &rn); |
737 | if (retval == TOMOYO_RETRY_REQUEST) | 884 | if (retval == TOMOYO_RETRY_REQUEST) |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index be2d3b935533..8a31f0c628b2 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -18,6 +18,7 @@ enum tomoyo_gc_id { | |||
18 | TOMOYO_ID_NUMBER_GROUP_MEMBER, | 18 | TOMOYO_ID_NUMBER_GROUP_MEMBER, |
19 | TOMOYO_ID_DOMAIN_INITIALIZER, | 19 | TOMOYO_ID_DOMAIN_INITIALIZER, |
20 | TOMOYO_ID_DOMAIN_KEEPER, | 20 | TOMOYO_ID_DOMAIN_KEEPER, |
21 | TOMOYO_ID_AGGREGATOR, | ||
21 | TOMOYO_ID_ALIAS, | 22 | TOMOYO_ID_ALIAS, |
22 | TOMOYO_ID_GLOBALLY_READABLE, | 23 | TOMOYO_ID_GLOBALLY_READABLE, |
23 | TOMOYO_ID_PATTERN, | 24 | TOMOYO_ID_PATTERN, |
@@ -77,6 +78,12 @@ static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) | |||
77 | tomoyo_put_name(ptr->program); | 78 | tomoyo_put_name(ptr->program); |
78 | } | 79 | } |
79 | 80 | ||
81 | static void tomoyo_del_aggregator(struct tomoyo_aggregator_entry *ptr) | ||
82 | { | ||
83 | tomoyo_put_name(ptr->original_name); | ||
84 | tomoyo_put_name(ptr->aggregated_name); | ||
85 | } | ||
86 | |||
80 | static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) | 87 | static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) |
81 | { | 88 | { |
82 | tomoyo_put_name(ptr->original_name); | 89 | tomoyo_put_name(ptr->original_name); |
@@ -264,6 +271,17 @@ static void tomoyo_collect_entry(void) | |||
264 | } | 271 | } |
265 | } | 272 | } |
266 | { | 273 | { |
274 | struct tomoyo_aggregator_entry *ptr; | ||
275 | list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) { | ||
276 | if (!ptr->is_deleted) | ||
277 | continue; | ||
278 | if (tomoyo_add_to_gc(TOMOYO_ID_AGGREGATOR, ptr)) | ||
279 | list_del_rcu(&ptr->list); | ||
280 | else | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | { | ||
267 | struct tomoyo_alias_entry *ptr; | 285 | struct tomoyo_alias_entry *ptr; |
268 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | 286 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { |
269 | if (!ptr->is_deleted) | 287 | if (!ptr->is_deleted) |
@@ -417,6 +435,9 @@ static void tomoyo_kfree_entry(void) | |||
417 | case TOMOYO_ID_DOMAIN_KEEPER: | 435 | case TOMOYO_ID_DOMAIN_KEEPER: |
418 | tomoyo_del_domain_keeper(p->element); | 436 | tomoyo_del_domain_keeper(p->element); |
419 | break; | 437 | break; |
438 | case TOMOYO_ID_AGGREGATOR: | ||
439 | tomoyo_del_aggregator(p->element); | ||
440 | break; | ||
420 | case TOMOYO_ID_ALIAS: | 441 | case TOMOYO_ID_ALIAS: |
421 | tomoyo_del_alias(p->element); | 442 | tomoyo_del_alias(p->element); |
422 | break; | 443 | break; |