aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2010-06-03 07:38:03 -0400
committerJames Morris <jmorris@namei.org>2010-08-02 01:33:42 -0400
commit1084307ca097745ed6e40a192329b133a49271ac (patch)
treef3b2e81705afb4ca3006ebb931aa0aad426ace02
parent3f629636320dfa65804779a3fc333f3147f3b064 (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>
-rw-r--r--security/tomoyo/common.c4
-rw-r--r--security/tomoyo/common.h32
-rw-r--r--security/tomoyo/domain.c147
-rw-r--r--security/tomoyo/gc.c21
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 */
607struct 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);
694bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num); 713bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
695 714
715/* Read "aggregator" entry in exception policy. */
716bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head);
696/* Read "alias" entry in exception policy. */ 717/* Read "alias" entry in exception policy. */
697bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head); 718bool 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. */
731int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, 752int 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. */
755int tomoyo_write_aggregator_policy(char *data, const bool is_delete);
733/* Create "alias" entry in exception policy. */ 756/* Create "alias" entry in exception policy. */
734int tomoyo_write_alias_policy(char *data, const bool is_delete); 757int tomoyo_write_alias_policy(char *data, const bool is_delete);
735/* 758/*
@@ -857,6 +880,7 @@ extern struct list_head tomoyo_path_group_list;
857extern struct list_head tomoyo_number_group_list; 880extern struct list_head tomoyo_number_group_list;
858extern struct list_head tomoyo_domain_initializer_list; 881extern struct list_head tomoyo_domain_initializer_list;
859extern struct list_head tomoyo_domain_keeper_list; 882extern struct list_head tomoyo_domain_keeper_list;
883extern struct list_head tomoyo_aggregator_list;
860extern struct list_head tomoyo_alias_list; 884extern struct list_head tomoyo_alias_list;
861extern struct list_head tomoyo_globally_readable_list; 885extern struct list_head tomoyo_globally_readable_list;
862extern struct list_head tomoyo_pattern_list; 886extern 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
1063static 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
1039static inline bool tomoyo_is_same_alias_entry 1071static 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 */
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/*
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
81static 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
80static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) 87static 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;