aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2010-06-12 07:46:22 -0400
committerJames Morris <jmorris@namei.org>2010-08-02 01:34:28 -0400
commit237ab459f12cb98eadd3fe7b85343e183a1076a4 (patch)
treef2835e2945016beb4e29b6a2ed8f9d372dc1b412 /security/tomoyo
parent927942aabbbe506bf9bc70a16dc5460ecc64c148 (diff)
TOMOYO: Use callback for updating entries.
Use common "struct list_head" + "bool" + "u8" structure and use common code for elements using that structure. 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.c4
-rw-r--r--security/tomoyo/common.h82
-rw-r--r--security/tomoyo/domain.c51
-rw-r--r--security/tomoyo/file.c349
-rw-r--r--security/tomoyo/gc.c28
-rw-r--r--security/tomoyo/mount.c43
-rw-r--r--security/tomoyo/util.c8
7 files changed, 253 insertions, 312 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 811adb5e9fea..6556e5d27d74 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -950,8 +950,6 @@ static bool tomoyo_print_mount_acl(struct tomoyo_io_buffer *head,
950 struct tomoyo_mount_acl *ptr) 950 struct tomoyo_mount_acl *ptr)
951{ 951{
952 const int pos = head->read_avail; 952 const int pos = head->read_avail;
953 if (ptr->is_deleted)
954 return true;
955 if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) || 953 if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) ||
956 !tomoyo_print_name_union(head, &ptr->dev_name) || 954 !tomoyo_print_name_union(head, &ptr->dev_name) ||
957 !tomoyo_print_name_union(head, &ptr->dir_name) || 955 !tomoyo_print_name_union(head, &ptr->dir_name) ||
@@ -977,6 +975,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
977{ 975{
978 const u8 acl_type = ptr->type; 976 const u8 acl_type = ptr->type;
979 977
978 if (ptr->is_deleted)
979 return true;
980 if (acl_type == TOMOYO_TYPE_PATH_ACL) { 980 if (acl_type == TOMOYO_TYPE_PATH_ACL) {
981 struct tomoyo_path_acl *acl 981 struct tomoyo_path_acl *acl
982 = container_of(ptr, struct tomoyo_path_acl, head); 982 = container_of(ptr, struct tomoyo_path_acl, head);
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index c777c594a00b..539b9a28b739 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -112,6 +112,8 @@ enum tomoyo_path_acl_index {
112 TOMOYO_MAX_PATH_OPERATION 112 TOMOYO_MAX_PATH_OPERATION
113}; 113};
114 114
115#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE))
116
115enum tomoyo_path_number3_acl_index { 117enum tomoyo_path_number3_acl_index {
116 TOMOYO_TYPE_MKBLOCK, 118 TOMOYO_TYPE_MKBLOCK,
117 TOMOYO_TYPE_MKCHAR, 119 TOMOYO_TYPE_MKCHAR,
@@ -289,17 +291,19 @@ struct tomoyo_number_group_member {
289 * 291 *
290 * (1) "list" which is linked to the ->acl_info_list of 292 * (1) "list" which is linked to the ->acl_info_list of
291 * "struct tomoyo_domain_info" 293 * "struct tomoyo_domain_info"
292 * (2) "type" which tells type of the entry (either 294 * (2) "is_deleted" is a bool which is true if this domain is marked as
293 * "struct tomoyo_path_acl" or "struct tomoyo_path2_acl"). 295 * "deleted", false otherwise.
296 * (3) "type" which tells type of the entry.
294 * 297 *
295 * Packing "struct tomoyo_acl_info" allows 298 * Packing "struct tomoyo_acl_info" allows
296 * "struct tomoyo_path_acl" to embed "u8" + "u16" and 299 * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl"
297 * "struct tomoyo_path2_acl" to embed "u8" 300 * "struct tomoyo_path_number_acl" "struct tomoyo_path_number3_acl" to embed
298 * without enlarging their structure size. 301 * "u8" without enlarging their structure size.
299 */ 302 */
300struct tomoyo_acl_info { 303struct tomoyo_acl_info {
301 struct list_head list; 304 struct list_head list;
302 u8 type; 305 bool is_deleted;
306 u8 type; /* = one of values in "enum tomoyo_acl_entry_type_index". */
303} __packed; 307} __packed;
304 308
305/* 309/*
@@ -438,17 +442,15 @@ struct tomoyo_path2_acl {
438 * It has following fields. 442 * It has following fields.
439 * 443 *
440 * (1) "head" which is a "struct tomoyo_acl_info". 444 * (1) "head" which is a "struct tomoyo_acl_info".
441 * (2) "is_deleted" is boolean. 445 * (2) "dev_name" is the device name.
442 * (3) "dev_name" is the device name. 446 * (3) "dir_name" is the mount point.
443 * (4) "dir_name" is the mount point. 447 * (4) "fs_type" is the filesystem type.
444 * (5) "flags" is the mount flags. 448 * (5) "flags" is the mount flags.
445 * 449 *
446 * Directives held by this structure are "allow_rename", "allow_link" and 450 * Directive held by this structure is "allow_mount".
447 * "allow_pivot_root".
448 */ 451 */
449struct tomoyo_mount_acl { 452struct tomoyo_mount_acl {
450 struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */ 453 struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
451 bool is_deleted;
452 struct tomoyo_name_union dev_name; 454 struct tomoyo_name_union dev_name;
453 struct tomoyo_name_union dir_name; 455 struct tomoyo_name_union dir_name;
454 struct tomoyo_name_union fs_type; 456 struct tomoyo_name_union fs_type;
@@ -914,6 +916,16 @@ void tomoyo_run_gc(void);
914 916
915void tomoyo_memory_free(void *ptr); 917void tomoyo_memory_free(void *ptr);
916 918
919int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
920 bool is_delete, struct tomoyo_domain_info *domain,
921 bool (*check_duplicate) (const struct tomoyo_acl_info
922 *,
923 const struct tomoyo_acl_info
924 *),
925 bool (*merge_duplicate) (struct tomoyo_acl_info *,
926 struct tomoyo_acl_info *,
927 const bool));
928
917/********** External variable definitions. **********/ 929/********** External variable definitions. **********/
918 930
919/* Lock for GC. */ 931/* Lock for GC. */
@@ -1042,52 +1054,6 @@ static inline bool tomoyo_is_same_number_union
1042 p1->max_type == p2->max_type && p1->is_group == p2->is_group; 1054 p1->max_type == p2->max_type && p1->is_group == p2->is_group;
1043} 1055}
1044 1056
1045static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
1046 const struct tomoyo_path_acl *p2)
1047{
1048 return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
1049 tomoyo_is_same_name_union(&p1->name, &p2->name);
1050}
1051
1052static inline bool tomoyo_is_same_path_number3_acl
1053(const struct tomoyo_path_number3_acl *p1,
1054 const struct tomoyo_path_number3_acl *p2)
1055{
1056 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
1057 && tomoyo_is_same_name_union(&p1->name, &p2->name)
1058 && tomoyo_is_same_number_union(&p1->mode, &p2->mode)
1059 && tomoyo_is_same_number_union(&p1->major, &p2->major)
1060 && tomoyo_is_same_number_union(&p1->minor, &p2->minor);
1061}
1062
1063
1064static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
1065 const struct tomoyo_path2_acl *p2)
1066{
1067 return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
1068 tomoyo_is_same_name_union(&p1->name1, &p2->name1) &&
1069 tomoyo_is_same_name_union(&p1->name2, &p2->name2);
1070}
1071
1072static inline bool tomoyo_is_same_path_number_acl
1073(const struct tomoyo_path_number_acl *p1,
1074 const struct tomoyo_path_number_acl *p2)
1075{
1076 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
1077 && tomoyo_is_same_name_union(&p1->name, &p2->name)
1078 && tomoyo_is_same_number_union(&p1->number, &p2->number);
1079}
1080
1081static inline bool tomoyo_is_same_mount_acl(const struct tomoyo_mount_acl *p1,
1082 const struct tomoyo_mount_acl *p2)
1083{
1084 return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
1085 tomoyo_is_same_name_union(&p1->dev_name, &p2->dev_name) &&
1086 tomoyo_is_same_name_union(&p1->dir_name, &p2->dir_name) &&
1087 tomoyo_is_same_name_union(&p1->fs_type, &p2->fs_type) &&
1088 tomoyo_is_same_number_union(&p1->flags, &p2->flags);
1089}
1090
1091static inline bool tomoyo_is_same_domain_initializer_entry 1057static inline bool tomoyo_is_same_domain_initializer_entry
1092(const struct tomoyo_domain_initializer_entry *p1, 1058(const struct tomoyo_domain_initializer_entry *p1,
1093 const struct tomoyo_domain_initializer_entry *p2) 1059 const struct tomoyo_domain_initializer_entry *p2)
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 09ec37c12a9c..f774e73e0022 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -15,6 +15,57 @@
15/* The initial domain. */ 15/* The initial domain. */
16struct tomoyo_domain_info tomoyo_kernel_domain; 16struct tomoyo_domain_info tomoyo_kernel_domain;
17 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
18/* 69/*
19 * tomoyo_domain_list is used for holding list of domains. 70 * tomoyo_domain_list is used for holding list of domains.
20 * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding 71 * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 8e51348d022e..b826058c72e9 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -665,50 +665,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
665} 665}
666 666
667/** 667/**
668 * tomoyo_update_file_acl - Update file's read/write/execute ACL.
669 *
670 * @perm: Permission (between 1 to 7).
671 * @filename: Filename.
672 * @domain: Pointer to "struct tomoyo_domain_info".
673 * @is_delete: True if it is a delete request.
674 *
675 * Returns 0 on success, negative value otherwise.
676 *
677 * This is legacy support interface for older policy syntax.
678 * Current policy syntax uses "allow_read/write" instead of "6",
679 * "allow_read" instead of "4", "allow_write" instead of "2",
680 * "allow_execute" instead of "1".
681 *
682 * Caller holds tomoyo_read_lock().
683 */
684static int tomoyo_update_file_acl(u8 perm, const char *filename,
685 struct tomoyo_domain_info * const domain,
686 const bool is_delete)
687{
688 if (perm > 7 || !perm) {
689 printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
690 __func__, perm, filename);
691 return -EINVAL;
692 }
693 if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
694 /*
695 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
696 * directory permissions.
697 */
698 return 0;
699 if (perm & 4)
700 tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
701 is_delete);
702 if (perm & 2)
703 tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
704 is_delete);
705 if (perm & 1)
706 tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
707 is_delete);
708 return 0;
709}
710
711/**
712 * tomoyo_path_acl - Check permission for single path operation. 668 * tomoyo_path_acl - Check permission for single path operation.
713 * 669 *
714 * @r: Pointer to "struct tomoyo_request_info". 670 * @r: Pointer to "struct tomoyo_request_info".
@@ -797,6 +753,40 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r,
797 return error; 753 return error;
798} 754}
799 755
756static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
757 const struct tomoyo_acl_info *b)
758{
759 const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
760 const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
761 return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
762 tomoyo_is_same_name_union(&p1->name, &p2->name);
763}
764
765static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
766 struct tomoyo_acl_info *b,
767 const bool is_delete)
768{
769 u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
770 ->perm;
771 u16 perm = *a_perm;
772 const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
773 if (is_delete) {
774 perm &= ~b_perm;
775 if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
776 perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
777 else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
778 perm &= ~TOMOYO_RW_MASK;
779 } else {
780 perm |= b_perm;
781 if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
782 perm |= (1 << TOMOYO_TYPE_READ_WRITE);
783 else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
784 perm |= TOMOYO_RW_MASK;
785 }
786 *a_perm = perm;
787 return !perm;
788}
789
800/** 790/**
801 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 791 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
802 * 792 *
@@ -810,63 +800,56 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r,
810 * Caller holds tomoyo_read_lock(). 800 * Caller holds tomoyo_read_lock().
811 */ 801 */
812static int tomoyo_update_path_acl(const u8 type, const char *filename, 802static int tomoyo_update_path_acl(const u8 type, const char *filename,
813 struct tomoyo_domain_info *const domain, 803 struct tomoyo_domain_info * const domain,
814 const bool is_delete) 804 const bool is_delete)
815{ 805{
816 static const u16 tomoyo_rw_mask =
817 (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
818 const u16 perm = 1 << type;
819 struct tomoyo_acl_info *ptr;
820 struct tomoyo_path_acl e = { 806 struct tomoyo_path_acl e = {
821 .head.type = TOMOYO_TYPE_PATH_ACL, 807 .head.type = TOMOYO_TYPE_PATH_ACL,
822 .perm = perm 808 .perm = 1 << type
823 }; 809 };
824 int error = is_delete ? -ENOENT : -ENOMEM; 810 int error;
825 811 if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
826 if (type == TOMOYO_TYPE_READ_WRITE) 812 e.perm |= TOMOYO_RW_MASK;
827 e.perm |= tomoyo_rw_mask;
828 if (!domain)
829 return -EINVAL;
830 if (!tomoyo_parse_name_union(filename, &e.name)) 813 if (!tomoyo_parse_name_union(filename, &e.name))
831 return -EINVAL; 814 return -EINVAL;
832 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 815 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
833 goto out; 816 tomoyo_same_path_acl,
834 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 817 tomoyo_merge_path_acl);
835 struct tomoyo_path_acl *acl =
836 container_of(ptr, struct tomoyo_path_acl, head);
837 if (!tomoyo_is_same_path_acl(acl, &e))
838 continue;
839 if (is_delete) {
840 acl->perm &= ~perm;
841 if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
842 acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
843 else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
844 acl->perm &= ~tomoyo_rw_mask;
845 } else {
846 acl->perm |= perm;
847 if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
848 acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
849 else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
850 acl->perm |= tomoyo_rw_mask;
851 }
852 error = 0;
853 break;
854 }
855 if (!is_delete && error) {
856 struct tomoyo_path_acl *entry =
857 tomoyo_commit_ok(&e, sizeof(e));
858 if (entry) {
859 list_add_tail_rcu(&entry->head.list,
860 &domain->acl_info_list);
861 error = 0;
862 }
863 }
864 mutex_unlock(&tomoyo_policy_lock);
865 out:
866 tomoyo_put_name_union(&e.name); 818 tomoyo_put_name_union(&e.name);
867 return error; 819 return error;
868} 820}
869 821
822static bool tomoyo_same_path_number3_acl(const struct tomoyo_acl_info *a,
823 const struct tomoyo_acl_info *b)
824{
825 const struct tomoyo_path_number3_acl *p1 = container_of(a, typeof(*p1),
826 head);
827 const struct tomoyo_path_number3_acl *p2 = container_of(b, typeof(*p2),
828 head);
829 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
830 && tomoyo_is_same_name_union(&p1->name, &p2->name)
831 && tomoyo_is_same_number_union(&p1->mode, &p2->mode)
832 && tomoyo_is_same_number_union(&p1->major, &p2->major)
833 && tomoyo_is_same_number_union(&p1->minor, &p2->minor);
834}
835
836static bool tomoyo_merge_path_number3_acl(struct tomoyo_acl_info *a,
837 struct tomoyo_acl_info *b,
838 const bool is_delete)
839{
840 u8 *const a_perm = &container_of(a, struct tomoyo_path_number3_acl,
841 head)->perm;
842 u8 perm = *a_perm;
843 const u8 b_perm = container_of(b, struct tomoyo_path_number3_acl, head)
844 ->perm;
845 if (is_delete)
846 perm &= ~b_perm;
847 else
848 perm |= b_perm;
849 *a_perm = perm;
850 return !perm;
851}
852
870/** 853/**
871 * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. 854 * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list.
872 * 855 *
@@ -879,20 +862,17 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
879 * @is_delete: True if it is a delete request. 862 * @is_delete: True if it is a delete request.
880 * 863 *
881 * Returns 0 on success, negative value otherwise. 864 * Returns 0 on success, negative value otherwise.
865 *
866 * Caller holds tomoyo_read_lock().
882 */ 867 */
883static inline int tomoyo_update_path_number3_acl(const u8 type, 868static int tomoyo_update_path_number3_acl(const u8 type, const char *filename,
884 const char *filename, 869 char *mode, char *major, char *minor,
885 char *mode, 870 struct tomoyo_domain_info * const
886 char *major, char *minor, 871 domain, const bool is_delete)
887 struct tomoyo_domain_info *
888 const domain,
889 const bool is_delete)
890{ 872{
891 const u8 perm = 1 << type;
892 struct tomoyo_acl_info *ptr;
893 struct tomoyo_path_number3_acl e = { 873 struct tomoyo_path_number3_acl e = {
894 .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, 874 .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL,
895 .perm = perm 875 .perm = 1 << type
896 }; 876 };
897 int error = is_delete ? -ENOENT : -ENOMEM; 877 int error = is_delete ? -ENOENT : -ENOMEM;
898 if (!tomoyo_parse_name_union(filename, &e.name) || 878 if (!tomoyo_parse_name_union(filename, &e.name) ||
@@ -900,30 +880,9 @@ static inline int tomoyo_update_path_number3_acl(const u8 type,
900 !tomoyo_parse_number_union(major, &e.major) || 880 !tomoyo_parse_number_union(major, &e.major) ||
901 !tomoyo_parse_number_union(minor, &e.minor)) 881 !tomoyo_parse_number_union(minor, &e.minor))
902 goto out; 882 goto out;
903 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 883 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
904 goto out; 884 tomoyo_same_path_number3_acl,
905 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 885 tomoyo_merge_path_number3_acl);
906 struct tomoyo_path_number3_acl *acl =
907 container_of(ptr, struct tomoyo_path_number3_acl, head);
908 if (!tomoyo_is_same_path_number3_acl(acl, &e))
909 continue;
910 if (is_delete)
911 acl->perm &= ~perm;
912 else
913 acl->perm |= perm;
914 error = 0;
915 break;
916 }
917 if (!is_delete && error) {
918 struct tomoyo_path_number3_acl *entry =
919 tomoyo_commit_ok(&e, sizeof(e));
920 if (entry) {
921 list_add_tail_rcu(&entry->head.list,
922 &domain->acl_info_list);
923 error = 0;
924 }
925 }
926 mutex_unlock(&tomoyo_policy_lock);
927 out: 886 out:
928 tomoyo_put_name_union(&e.name); 887 tomoyo_put_name_union(&e.name);
929 tomoyo_put_number_union(&e.mode); 888 tomoyo_put_number_union(&e.mode);
@@ -932,6 +891,32 @@ static inline int tomoyo_update_path_number3_acl(const u8 type,
932 return error; 891 return error;
933} 892}
934 893
894static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
895 const struct tomoyo_acl_info *b)
896{
897 const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
898 const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
899 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
900 && tomoyo_is_same_name_union(&p1->name1, &p2->name1)
901 && tomoyo_is_same_name_union(&p1->name2, &p2->name2);
902}
903
904static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
905 struct tomoyo_acl_info *b,
906 const bool is_delete)
907{
908 u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
909 ->perm;
910 u8 perm = *a_perm;
911 const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
912 if (is_delete)
913 perm &= ~b_perm;
914 else
915 perm |= b_perm;
916 *a_perm = perm;
917 return !perm;
918}
919
935/** 920/**
936 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 921 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
937 * 922 *
@@ -947,46 +932,20 @@ static inline int tomoyo_update_path_number3_acl(const u8 type,
947 */ 932 */
948static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 933static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
949 const char *filename2, 934 const char *filename2,
950 struct tomoyo_domain_info *const domain, 935 struct tomoyo_domain_info * const domain,
951 const bool is_delete) 936 const bool is_delete)
952{ 937{
953 const u8 perm = 1 << type;
954 struct tomoyo_path2_acl e = { 938 struct tomoyo_path2_acl e = {
955 .head.type = TOMOYO_TYPE_PATH2_ACL, 939 .head.type = TOMOYO_TYPE_PATH2_ACL,
956 .perm = perm 940 .perm = 1 << type
957 }; 941 };
958 struct tomoyo_acl_info *ptr;
959 int error = is_delete ? -ENOENT : -ENOMEM; 942 int error = is_delete ? -ENOENT : -ENOMEM;
960
961 if (!domain)
962 return -EINVAL;
963 if (!tomoyo_parse_name_union(filename1, &e.name1) || 943 if (!tomoyo_parse_name_union(filename1, &e.name1) ||
964 !tomoyo_parse_name_union(filename2, &e.name2)) 944 !tomoyo_parse_name_union(filename2, &e.name2))
965 goto out; 945 goto out;
966 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 946 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
967 goto out; 947 tomoyo_same_path2_acl,
968 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 948 tomoyo_merge_path2_acl);
969 struct tomoyo_path2_acl *acl =
970 container_of(ptr, struct tomoyo_path2_acl, head);
971 if (!tomoyo_is_same_path2_acl(acl, &e))
972 continue;
973 if (is_delete)
974 acl->perm &= ~perm;
975 else
976 acl->perm |= perm;
977 error = 0;
978 break;
979 }
980 if (!is_delete && error) {
981 struct tomoyo_path2_acl *entry =
982 tomoyo_commit_ok(&e, sizeof(e));
983 if (entry) {
984 list_add_tail_rcu(&entry->head.list,
985 &domain->acl_info_list);
986 error = 0;
987 }
988 }
989 mutex_unlock(&tomoyo_policy_lock);
990 out: 949 out:
991 tomoyo_put_name_union(&e.name1); 950 tomoyo_put_name_union(&e.name1);
992 tomoyo_put_name_union(&e.name2); 951 tomoyo_put_name_union(&e.name2);
@@ -1157,6 +1116,35 @@ static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
1157 return error; 1116 return error;
1158} 1117}
1159 1118
1119static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
1120 const struct tomoyo_acl_info *b)
1121{
1122 const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
1123 head);
1124 const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
1125 head);
1126 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
1127 && tomoyo_is_same_name_union(&p1->name, &p2->name)
1128 && tomoyo_is_same_number_union(&p1->number, &p2->number);
1129}
1130
1131static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
1132 struct tomoyo_acl_info *b,
1133 const bool is_delete)
1134{
1135 u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
1136 head)->perm;
1137 u8 perm = *a_perm;
1138 const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
1139 ->perm;
1140 if (is_delete)
1141 perm &= ~b_perm;
1142 else
1143 perm |= b_perm;
1144 *a_perm = perm;
1145 return !perm;
1146}
1147
1160/** 1148/**
1161 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1149 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
1162 * 1150 *
@@ -1168,50 +1156,24 @@ static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
1168 * 1156 *
1169 * Returns 0 on success, negative value otherwise. 1157 * Returns 0 on success, negative value otherwise.
1170 */ 1158 */
1171static inline int tomoyo_update_path_number_acl(const u8 type, 1159static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
1172 const char *filename, 1160 char *number,
1173 char *number, 1161 struct tomoyo_domain_info * const
1174 struct tomoyo_domain_info * 1162 domain,
1175 const domain, 1163 const bool is_delete)
1176 const bool is_delete)
1177{ 1164{
1178 const u8 perm = 1 << type;
1179 struct tomoyo_acl_info *ptr;
1180 struct tomoyo_path_number_acl e = { 1165 struct tomoyo_path_number_acl e = {
1181 .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1166 .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
1182 .perm = perm 1167 .perm = 1 << type
1183 }; 1168 };
1184 int error = is_delete ? -ENOENT : -ENOMEM; 1169 int error = is_delete ? -ENOENT : -ENOMEM;
1185 if (!domain)
1186 return -EINVAL;
1187 if (!tomoyo_parse_name_union(filename, &e.name)) 1170 if (!tomoyo_parse_name_union(filename, &e.name))
1188 return -EINVAL; 1171 return -EINVAL;
1189 if (!tomoyo_parse_number_union(number, &e.number)) 1172 if (!tomoyo_parse_number_union(number, &e.number))
1190 goto out; 1173 goto out;
1191 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1174 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
1192 goto out; 1175 tomoyo_same_path_number_acl,
1193 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1176 tomoyo_merge_path_number_acl);
1194 struct tomoyo_path_number_acl *acl =
1195 container_of(ptr, struct tomoyo_path_number_acl, head);
1196 if (!tomoyo_is_same_path_number_acl(acl, &e))
1197 continue;
1198 if (is_delete)
1199 acl->perm &= ~perm;
1200 else
1201 acl->perm |= perm;
1202 error = 0;
1203 break;
1204 }
1205 if (!is_delete && error) {
1206 struct tomoyo_path_number_acl *entry =
1207 tomoyo_commit_ok(&e, sizeof(e));
1208 if (entry) {
1209 list_add_tail_rcu(&entry->head.list,
1210 &domain->acl_info_list);
1211 error = 0;
1212 }
1213 }
1214 mutex_unlock(&tomoyo_policy_lock);
1215 out: 1177 out:
1216 tomoyo_put_name_union(&e.name); 1178 tomoyo_put_name_union(&e.name);
1217 tomoyo_put_number_union(&e.number); 1179 tomoyo_put_number_union(&e.number);
@@ -1585,13 +1547,8 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
1585 u8 type; 1547 u8 type;
1586 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1548 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
1587 return -EINVAL; 1549 return -EINVAL;
1588 if (strncmp(w[0], "allow_", 6)) { 1550 if (strncmp(w[0], "allow_", 6))
1589 unsigned int perm;
1590 if (sscanf(w[0], "%u", &perm) == 1)
1591 return tomoyo_update_file_acl((u8) perm, w[1], domain,
1592 is_delete);
1593 goto out; 1551 goto out;
1594 }
1595 w[0] += 6; 1552 w[0] += 6;
1596 for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1553 for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
1597 if (strcmp(w[0], tomoyo_path_keyword[type])) 1554 if (strcmp(w[0], tomoyo_path_keyword[type]))
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index 8a31f0c628b2..aed7ddd0de84 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -310,34 +310,8 @@ static void tomoyo_collect_entry(void)
310 struct tomoyo_acl_info *acl; 310 struct tomoyo_acl_info *acl;
311 list_for_each_entry_rcu(acl, &domain->acl_info_list, 311 list_for_each_entry_rcu(acl, &domain->acl_info_list,
312 list) { 312 list) {
313 switch (acl->type) { 313 if (!acl->is_deleted)
314 case TOMOYO_TYPE_PATH_ACL:
315 if (container_of(acl,
316 struct tomoyo_path_acl,
317 head)->perm)
318 continue;
319 break;
320 case TOMOYO_TYPE_PATH2_ACL:
321 if (container_of(acl,
322 struct tomoyo_path2_acl,
323 head)->perm)
324 continue;
325 break;
326 case TOMOYO_TYPE_PATH_NUMBER_ACL:
327 if (container_of(acl,
328 struct tomoyo_path_number_acl,
329 head)->perm)
330 continue;
331 break;
332 case TOMOYO_TYPE_PATH_NUMBER3_ACL:
333 if (container_of(acl,
334 struct tomoyo_path_number3_acl,
335 head)->perm)
336 continue;
337 break;
338 default:
339 continue; 314 continue;
340 }
341 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) 315 if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
342 list_del_rcu(&acl->list); 316 list_del_rcu(&acl->list);
343 else 317 else
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index 77ee8bf41948..c170b41c3833 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -114,11 +114,10 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name,
114 tomoyo_fill_path_info(&rdev); 114 tomoyo_fill_path_info(&rdev);
115 list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) { 115 list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) {
116 struct tomoyo_mount_acl *acl; 116 struct tomoyo_mount_acl *acl;
117 if (ptr->type != TOMOYO_TYPE_MOUNT_ACL) 117 if (ptr->is_deleted || ptr->type != TOMOYO_TYPE_MOUNT_ACL)
118 continue; 118 continue;
119 acl = container_of(ptr, struct tomoyo_mount_acl, head); 119 acl = container_of(ptr, struct tomoyo_mount_acl, head);
120 if (acl->is_deleted || 120 if (!tomoyo_compare_number_union(flags, &acl->flags) ||
121 !tomoyo_compare_number_union(flags, &acl->flags) ||
122 !tomoyo_compare_name_union(&rtype, &acl->fs_type) || 121 !tomoyo_compare_name_union(&rtype, &acl->fs_type) ||
123 !tomoyo_compare_name_union(&rdir, &acl->dir_name) || 122 !tomoyo_compare_name_union(&rdir, &acl->dir_name) ||
124 (need_dev && 123 (need_dev &&
@@ -259,6 +258,18 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
259 return error; 258 return error;
260} 259}
261 260
261static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
262 const struct tomoyo_acl_info *b)
263{
264 const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
265 const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
266 return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
267 tomoyo_is_same_name_union(&p1->dev_name, &p2->dev_name) &&
268 tomoyo_is_same_name_union(&p1->dir_name, &p2->dir_name) &&
269 tomoyo_is_same_name_union(&p1->fs_type, &p2->fs_type) &&
270 tomoyo_is_same_number_union(&p1->flags, &p2->flags);
271}
272
262/** 273/**
263 * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list. 274 * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list.
264 * 275 *
@@ -267,11 +278,12 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
267 * @is_delete: True if it is a delete request. 278 * @is_delete: True if it is a delete request.
268 * 279 *
269 * Returns 0 on success, negative value otherwise. 280 * Returns 0 on success, negative value otherwise.
281 *
282 * Caller holds tomoyo_read_lock().
270 */ 283 */
271int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain, 284int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
272 const bool is_delete) 285 const bool is_delete)
273{ 286{
274 struct tomoyo_acl_info *ptr;
275 struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; 287 struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
276 int error = is_delete ? -ENOENT : -ENOMEM; 288 int error = is_delete ? -ENOENT : -ENOMEM;
277 char *w[4]; 289 char *w[4];
@@ -282,27 +294,8 @@ int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
282 !tomoyo_parse_name_union(w[2], &e.fs_type) || 294 !tomoyo_parse_name_union(w[2], &e.fs_type) ||
283 !tomoyo_parse_number_union(w[3], &e.flags)) 295 !tomoyo_parse_number_union(w[3], &e.flags))
284 goto out; 296 goto out;
285 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 297 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
286 goto out; 298 tomoyo_same_mount_acl, NULL);
287 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
288 struct tomoyo_mount_acl *acl =
289 container_of(ptr, struct tomoyo_mount_acl, head);
290 if (!tomoyo_is_same_mount_acl(acl, &e))
291 continue;
292 acl->is_deleted = is_delete;
293 error = 0;
294 break;
295 }
296 if (!is_delete && error) {
297 struct tomoyo_mount_acl *entry =
298 tomoyo_commit_ok(&e, sizeof(e));
299 if (entry) {
300 list_add_tail_rcu(&entry->head.list,
301 &domain->acl_info_list);
302 error = 0;
303 }
304 }
305 mutex_unlock(&tomoyo_policy_lock);
306 out: 299 out:
307 tomoyo_put_name_union(&e.dev_name); 300 tomoyo_put_name_union(&e.dev_name);
308 tomoyo_put_name_union(&e.dir_name); 301 tomoyo_put_name_union(&e.dir_name);
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index 307793ed6075..e5931686ca33 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -911,6 +911,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
911 if (!domain) 911 if (!domain)
912 return true; 912 return true;
913 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 913 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
914 if (!ptr->is_deleted)
915 continue;
914 switch (ptr->type) { 916 switch (ptr->type) {
915 u16 perm; 917 u16 perm;
916 u8 i; 918 u8 i;
@@ -944,10 +946,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
944 if (perm & (1 << i)) 946 if (perm & (1 << i))
945 count++; 947 count++;
946 break; 948 break;
947 case TOMOYO_TYPE_MOUNT_ACL: 949 default:
948 if (!container_of(ptr, struct tomoyo_mount_acl, head)-> 950 count++;
949 is_deleted)
950 count++;
951 } 951 }
952 } 952 }
953 if (count < tomoyo_profile(domain->profile)->learning-> 953 if (count < tomoyo_profile(domain->profile)->learning->