Commit 237ab459f12cb98eadd3fe7b85343e183a1076a4
Committed by
James Morris
1 parent
927942aabb
Exists in
master
and in
4 other branches
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>
Showing 7 changed files with 253 additions and 312 deletions Side-by-side Diff
security/tomoyo/common.c
... | ... | @@ -950,8 +950,6 @@ |
950 | 950 | struct tomoyo_mount_acl *ptr) |
951 | 951 | { |
952 | 952 | const int pos = head->read_avail; |
953 | - if (ptr->is_deleted) | |
954 | - return true; | |
955 | 953 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) || |
956 | 954 | !tomoyo_print_name_union(head, &ptr->dev_name) || |
957 | 955 | !tomoyo_print_name_union(head, &ptr->dir_name) || |
... | ... | @@ -977,6 +975,8 @@ |
977 | 975 | { |
978 | 976 | const u8 acl_type = ptr->type; |
979 | 977 | |
978 | + if (ptr->is_deleted) | |
979 | + return true; | |
980 | 980 | if (acl_type == TOMOYO_TYPE_PATH_ACL) { |
981 | 981 | struct tomoyo_path_acl *acl |
982 | 982 | = container_of(ptr, struct tomoyo_path_acl, head); |
security/tomoyo/common.h
... | ... | @@ -112,6 +112,8 @@ |
112 | 112 | TOMOYO_MAX_PATH_OPERATION |
113 | 113 | }; |
114 | 114 | |
115 | +#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE)) | |
116 | + | |
115 | 117 | enum tomoyo_path_number3_acl_index { |
116 | 118 | TOMOYO_TYPE_MKBLOCK, |
117 | 119 | TOMOYO_TYPE_MKCHAR, |
118 | 120 | |
119 | 121 | |
... | ... | @@ -289,17 +291,19 @@ |
289 | 291 | * |
290 | 292 | * (1) "list" which is linked to the ->acl_info_list of |
291 | 293 | * "struct tomoyo_domain_info" |
292 | - * (2) "type" which tells type of the entry (either | |
293 | - * "struct tomoyo_path_acl" or "struct tomoyo_path2_acl"). | |
294 | + * (2) "is_deleted" is a bool which is true if this domain is marked as | |
295 | + * "deleted", false otherwise. | |
296 | + * (3) "type" which tells type of the entry. | |
294 | 297 | * |
295 | 298 | * Packing "struct tomoyo_acl_info" allows |
296 | - * "struct tomoyo_path_acl" to embed "u8" + "u16" and | |
297 | - * "struct tomoyo_path2_acl" to embed "u8" | |
298 | - * without enlarging their structure size. | |
299 | + * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl" | |
300 | + * "struct tomoyo_path_number_acl" "struct tomoyo_path_number3_acl" to embed | |
301 | + * "u8" without enlarging their structure size. | |
299 | 302 | */ |
300 | 303 | struct tomoyo_acl_info { |
301 | 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 | 307 | } __packed; |
304 | 308 | |
305 | 309 | /* |
306 | 310 | |
307 | 311 | |
... | ... | @@ -438,17 +442,15 @@ |
438 | 442 | * It has following fields. |
439 | 443 | * |
440 | 444 | * (1) "head" which is a "struct tomoyo_acl_info". |
441 | - * (2) "is_deleted" is boolean. | |
442 | - * (3) "dev_name" is the device name. | |
443 | - * (4) "dir_name" is the mount point. | |
445 | + * (2) "dev_name" is the device name. | |
446 | + * (3) "dir_name" is the mount point. | |
447 | + * (4) "fs_type" is the filesystem type. | |
444 | 448 | * (5) "flags" is the mount flags. |
445 | 449 | * |
446 | - * Directives held by this structure are "allow_rename", "allow_link" and | |
447 | - * "allow_pivot_root". | |
450 | + * Directive held by this structure is "allow_mount". | |
448 | 451 | */ |
449 | 452 | struct tomoyo_mount_acl { |
450 | 453 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */ |
451 | - bool is_deleted; | |
452 | 454 | struct tomoyo_name_union dev_name; |
453 | 455 | struct tomoyo_name_union dir_name; |
454 | 456 | struct tomoyo_name_union fs_type; |
... | ... | @@ -914,6 +916,16 @@ |
914 | 916 | |
915 | 917 | void tomoyo_memory_free(void *ptr); |
916 | 918 | |
919 | +int 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 | 929 | /********** External variable definitions. **********/ |
918 | 930 | |
919 | 931 | /* Lock for GC. */ |
... | ... | @@ -1040,52 +1052,6 @@ |
1040 | 1052 | return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1] |
1041 | 1053 | && p1->group == p2->group && p1->min_type == p2->min_type && |
1042 | 1054 | p1->max_type == p2->max_type && p1->is_group == p2->is_group; |
1043 | -} | |
1044 | - | |
1045 | -static 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 | - | |
1052 | -static 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 | - | |
1064 | -static 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 | - | |
1072 | -static 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 | - | |
1081 | -static 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 | 1055 | } |
1090 | 1056 | |
1091 | 1057 | static inline bool tomoyo_is_same_domain_initializer_entry |
security/tomoyo/domain.c
... | ... | @@ -15,6 +15,57 @@ |
15 | 15 | /* The initial domain. */ |
16 | 16 | struct 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 | + */ | |
32 | +int 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 | 70 | * tomoyo_domain_list is used for holding list of domains. |
20 | 71 | * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding |
security/tomoyo/file.c
... | ... | @@ -665,50 +665,6 @@ |
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 | - */ | |
684 | -static 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 | 668 | * tomoyo_path_acl - Check permission for single path operation. |
713 | 669 | * |
714 | 670 | * @r: Pointer to "struct tomoyo_request_info". |
... | ... | @@ -797,6 +753,40 @@ |
797 | 753 | return error; |
798 | 754 | } |
799 | 755 | |
756 | +static 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 | + | |
765 | +static 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 | 791 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
802 | 792 | * |
803 | 793 | |
804 | 794 | |
805 | 795 | |
806 | 796 | |
807 | 797 | |
... | ... | @@ -810,63 +800,56 @@ |
810 | 800 | * Caller holds tomoyo_read_lock(). |
811 | 801 | */ |
812 | 802 | static 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 | 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 | 806 | struct tomoyo_path_acl e = { |
821 | 807 | .head.type = TOMOYO_TYPE_PATH_ACL, |
822 | - .perm = perm | |
808 | + .perm = 1 << type | |
823 | 809 | }; |
824 | - int error = is_delete ? -ENOENT : -ENOMEM; | |
825 | - | |
826 | - if (type == TOMOYO_TYPE_READ_WRITE) | |
827 | - e.perm |= tomoyo_rw_mask; | |
828 | - if (!domain) | |
829 | - return -EINVAL; | |
810 | + int error; | |
811 | + if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) | |
812 | + e.perm |= TOMOYO_RW_MASK; | |
830 | 813 | if (!tomoyo_parse_name_union(filename, &e.name)) |
831 | 814 | return -EINVAL; |
832 | - if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
833 | - goto out; | |
834 | - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | |
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: | |
815 | + error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | |
816 | + tomoyo_same_path_acl, | |
817 | + tomoyo_merge_path_acl); | |
866 | 818 | tomoyo_put_name_union(&e.name); |
867 | 819 | return error; |
868 | 820 | } |
869 | 821 | |
822 | +static 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 | + | |
836 | +static 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 | 854 | * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. |
872 | 855 | * |
873 | 856 | |
874 | 857 | |
875 | 858 | |
... | ... | @@ -879,20 +862,17 @@ |
879 | 862 | * @is_delete: True if it is a delete request. |
880 | 863 | * |
881 | 864 | * Returns 0 on success, negative value otherwise. |
865 | + * | |
866 | + * Caller holds tomoyo_read_lock(). | |
882 | 867 | */ |
883 | -static inline int tomoyo_update_path_number3_acl(const u8 type, | |
884 | - const char *filename, | |
885 | - char *mode, | |
886 | - char *major, char *minor, | |
887 | - struct tomoyo_domain_info * | |
888 | - const domain, | |
889 | - const bool is_delete) | |
868 | +static int tomoyo_update_path_number3_acl(const u8 type, const char *filename, | |
869 | + char *mode, char *major, char *minor, | |
870 | + struct tomoyo_domain_info * const | |
871 | + domain, const bool is_delete) | |
890 | 872 | { |
891 | - const u8 perm = 1 << type; | |
892 | - struct tomoyo_acl_info *ptr; | |
893 | 873 | struct tomoyo_path_number3_acl e = { |
894 | 874 | .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, |
895 | - .perm = perm | |
875 | + .perm = 1 << type | |
896 | 876 | }; |
897 | 877 | int error = is_delete ? -ENOENT : -ENOMEM; |
898 | 878 | if (!tomoyo_parse_name_union(filename, &e.name) || |
... | ... | @@ -900,30 +880,9 @@ |
900 | 880 | !tomoyo_parse_number_union(major, &e.major) || |
901 | 881 | !tomoyo_parse_number_union(minor, &e.minor)) |
902 | 882 | goto out; |
903 | - if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
904 | - goto out; | |
905 | - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | |
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); | |
883 | + error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | |
884 | + tomoyo_same_path_number3_acl, | |
885 | + tomoyo_merge_path_number3_acl); | |
927 | 886 | out: |
928 | 887 | tomoyo_put_name_union(&e.name); |
929 | 888 | tomoyo_put_number_union(&e.mode); |
... | ... | @@ -932,6 +891,32 @@ |
932 | 891 | return error; |
933 | 892 | } |
934 | 893 | |
894 | +static 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 | + | |
904 | +static 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 | 921 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
937 | 922 | * |
938 | 923 | |
939 | 924 | |
940 | 925 | |
941 | 926 | |
942 | 927 | |
... | ... | @@ -947,46 +932,20 @@ |
947 | 932 | */ |
948 | 933 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
949 | 934 | const char *filename2, |
950 | - struct tomoyo_domain_info *const domain, | |
935 | + struct tomoyo_domain_info * const domain, | |
951 | 936 | const bool is_delete) |
952 | 937 | { |
953 | - const u8 perm = 1 << type; | |
954 | 938 | struct tomoyo_path2_acl e = { |
955 | 939 | .head.type = TOMOYO_TYPE_PATH2_ACL, |
956 | - .perm = perm | |
940 | + .perm = 1 << type | |
957 | 941 | }; |
958 | - struct tomoyo_acl_info *ptr; | |
959 | 942 | int error = is_delete ? -ENOENT : -ENOMEM; |
960 | - | |
961 | - if (!domain) | |
962 | - return -EINVAL; | |
963 | 943 | if (!tomoyo_parse_name_union(filename1, &e.name1) || |
964 | 944 | !tomoyo_parse_name_union(filename2, &e.name2)) |
965 | 945 | goto out; |
966 | - if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
967 | - goto out; | |
968 | - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | |
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); | |
946 | + error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | |
947 | + tomoyo_same_path2_acl, | |
948 | + tomoyo_merge_path2_acl); | |
990 | 949 | out: |
991 | 950 | tomoyo_put_name_union(&e.name1); |
992 | 951 | tomoyo_put_name_union(&e.name2); |
... | ... | @@ -1157,6 +1116,35 @@ |
1157 | 1116 | return error; |
1158 | 1117 | } |
1159 | 1118 | |
1119 | +static 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 | + | |
1131 | +static 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 | 1149 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. |
1162 | 1150 | * |
1163 | 1151 | |
1164 | 1152 | |
1165 | 1153 | |
1166 | 1154 | |
... | ... | @@ -1168,50 +1156,24 @@ |
1168 | 1156 | * |
1169 | 1157 | * Returns 0 on success, negative value otherwise. |
1170 | 1158 | */ |
1171 | -static inline int tomoyo_update_path_number_acl(const u8 type, | |
1172 | - const char *filename, | |
1173 | - char *number, | |
1174 | - struct tomoyo_domain_info * | |
1175 | - const domain, | |
1176 | - const bool is_delete) | |
1159 | +static int tomoyo_update_path_number_acl(const u8 type, const char *filename, | |
1160 | + char *number, | |
1161 | + struct tomoyo_domain_info * const | |
1162 | + domain, | |
1163 | + const bool is_delete) | |
1177 | 1164 | { |
1178 | - const u8 perm = 1 << type; | |
1179 | - struct tomoyo_acl_info *ptr; | |
1180 | 1165 | struct tomoyo_path_number_acl e = { |
1181 | 1166 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, |
1182 | - .perm = perm | |
1167 | + .perm = 1 << type | |
1183 | 1168 | }; |
1184 | 1169 | int error = is_delete ? -ENOENT : -ENOMEM; |
1185 | - if (!domain) | |
1186 | - return -EINVAL; | |
1187 | 1170 | if (!tomoyo_parse_name_union(filename, &e.name)) |
1188 | 1171 | return -EINVAL; |
1189 | 1172 | if (!tomoyo_parse_number_union(number, &e.number)) |
1190 | 1173 | goto out; |
1191 | - if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
1192 | - goto out; | |
1193 | - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | |
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); | |
1174 | + error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | |
1175 | + tomoyo_same_path_number_acl, | |
1176 | + tomoyo_merge_path_number_acl); | |
1215 | 1177 | out: |
1216 | 1178 | tomoyo_put_name_union(&e.name); |
1217 | 1179 | tomoyo_put_number_union(&e.number); |
1218 | 1180 | |
... | ... | @@ -1585,13 +1547,8 @@ |
1585 | 1547 | u8 type; |
1586 | 1548 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) |
1587 | 1549 | return -EINVAL; |
1588 | - 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); | |
1550 | + if (strncmp(w[0], "allow_", 6)) | |
1593 | 1551 | goto out; |
1594 | - } | |
1595 | 1552 | w[0] += 6; |
1596 | 1553 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { |
1597 | 1554 | if (strcmp(w[0], tomoyo_path_keyword[type])) |
security/tomoyo/gc.c
... | ... | @@ -310,34 +310,8 @@ |
310 | 310 | struct tomoyo_acl_info *acl; |
311 | 311 | list_for_each_entry_rcu(acl, &domain->acl_info_list, |
312 | 312 | list) { |
313 | - switch (acl->type) { | |
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: | |
313 | + if (!acl->is_deleted) | |
339 | 314 | continue; |
340 | - } | |
341 | 315 | if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) |
342 | 316 | list_del_rcu(&acl->list); |
343 | 317 | else |
security/tomoyo/mount.c
... | ... | @@ -114,11 +114,10 @@ |
114 | 114 | tomoyo_fill_path_info(&rdev); |
115 | 115 | list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) { |
116 | 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 | 118 | continue; |
119 | 119 | acl = container_of(ptr, struct tomoyo_mount_acl, head); |
120 | - if (acl->is_deleted || | |
121 | - !tomoyo_compare_number_union(flags, &acl->flags) || | |
120 | + if (!tomoyo_compare_number_union(flags, &acl->flags) || | |
122 | 121 | !tomoyo_compare_name_union(&rtype, &acl->fs_type) || |
123 | 122 | !tomoyo_compare_name_union(&rdir, &acl->dir_name) || |
124 | 123 | (need_dev && |
... | ... | @@ -259,6 +258,18 @@ |
259 | 258 | return error; |
260 | 259 | } |
261 | 260 | |
261 | +static 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 | 274 | * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list. |
264 | 275 | * |
265 | 276 | |
... | ... | @@ -267,11 +278,12 @@ |
267 | 278 | * @is_delete: True if it is a delete request. |
268 | 279 | * |
269 | 280 | * Returns 0 on success, negative value otherwise. |
281 | + * | |
282 | + * Caller holds tomoyo_read_lock(). | |
270 | 283 | */ |
271 | 284 | int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain, |
272 | 285 | const bool is_delete) |
273 | 286 | { |
274 | - struct tomoyo_acl_info *ptr; | |
275 | 287 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; |
276 | 288 | int error = is_delete ? -ENOENT : -ENOMEM; |
277 | 289 | char *w[4]; |
... | ... | @@ -282,27 +294,8 @@ |
282 | 294 | !tomoyo_parse_name_union(w[2], &e.fs_type) || |
283 | 295 | !tomoyo_parse_number_union(w[3], &e.flags)) |
284 | 296 | goto out; |
285 | - if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
286 | - goto out; | |
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); | |
297 | + error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | |
298 | + tomoyo_same_mount_acl, NULL); | |
306 | 299 | out: |
307 | 300 | tomoyo_put_name_union(&e.dev_name); |
308 | 301 | tomoyo_put_name_union(&e.dir_name); |
security/tomoyo/util.c
... | ... | @@ -911,6 +911,8 @@ |
911 | 911 | if (!domain) |
912 | 912 | return true; |
913 | 913 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
914 | + if (!ptr->is_deleted) | |
915 | + continue; | |
914 | 916 | switch (ptr->type) { |
915 | 917 | u16 perm; |
916 | 918 | u8 i; |
... | ... | @@ -944,10 +946,8 @@ |
944 | 946 | if (perm & (1 << i)) |
945 | 947 | count++; |
946 | 948 | break; |
947 | - case TOMOYO_TYPE_MOUNT_ACL: | |
948 | - if (!container_of(ptr, struct tomoyo_mount_acl, head)-> | |
949 | - is_deleted) | |
950 | - count++; | |
949 | + default: | |
950 | + count++; | |
951 | 951 | } |
952 | 952 | } |
953 | 953 | if (count < tomoyo_profile(domain->profile)->learning-> |