diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-05-16 21:09:15 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 01:33:37 -0400 |
commit | a1f9bb6a375a8dbf7797ffbd6739c46b338a77f7 (patch) | |
tree | 44df8f05e6ad6bd7cf9ce398c99efbd7cff24c20 /security/tomoyo/file.c | |
parent | cb0abe6a5b58499bd4bc1403f4987af9ead0642c (diff) |
TOMOYO: Split file access control functions by type of parameters.
Check numeric parameters for operations that deal them
(e.g. chmod/chown/ioctl).
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/file.c')
-rw-r--r-- | security/tomoyo/file.c | 588 |
1 files changed, 501 insertions, 87 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index f1d2adfd33bc..727cc723f87d 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -12,39 +12,49 @@ | |||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | /* Keyword array for single path operations. */ | 15 | /* Keyword array for operations with one pathname. */ |
16 | static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | 16 | static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
17 | [TOMOYO_TYPE_READ_WRITE] = "read/write", | 17 | [TOMOYO_TYPE_READ_WRITE] = "read/write", |
18 | [TOMOYO_TYPE_EXECUTE] = "execute", | 18 | [TOMOYO_TYPE_EXECUTE] = "execute", |
19 | [TOMOYO_TYPE_READ] = "read", | 19 | [TOMOYO_TYPE_READ] = "read", |
20 | [TOMOYO_TYPE_WRITE] = "write", | 20 | [TOMOYO_TYPE_WRITE] = "write", |
21 | [TOMOYO_TYPE_CREATE] = "create", | ||
22 | [TOMOYO_TYPE_UNLINK] = "unlink", | 21 | [TOMOYO_TYPE_UNLINK] = "unlink", |
23 | [TOMOYO_TYPE_MKDIR] = "mkdir", | ||
24 | [TOMOYO_TYPE_RMDIR] = "rmdir", | 22 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
25 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", | ||
26 | [TOMOYO_TYPE_MKSOCK] = "mksock", | ||
27 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", | ||
28 | [TOMOYO_TYPE_MKCHAR] = "mkchar", | ||
29 | [TOMOYO_TYPE_TRUNCATE] = "truncate", | 23 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
30 | [TOMOYO_TYPE_SYMLINK] = "symlink", | 24 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
31 | [TOMOYO_TYPE_REWRITE] = "rewrite", | 25 | [TOMOYO_TYPE_REWRITE] = "rewrite", |
32 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
33 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
34 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
35 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
36 | [TOMOYO_TYPE_CHROOT] = "chroot", | 26 | [TOMOYO_TYPE_CHROOT] = "chroot", |
37 | [TOMOYO_TYPE_MOUNT] = "mount", | 27 | [TOMOYO_TYPE_MOUNT] = "mount", |
38 | [TOMOYO_TYPE_UMOUNT] = "unmount", | 28 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
39 | }; | 29 | }; |
40 | 30 | ||
41 | /* Keyword array for double path operations. */ | 31 | /* Keyword array for operations with one pathname and three numbers. */ |
32 | static const char *tomoyo_path_number3_keyword | ||
33 | [TOMOYO_MAX_PATH_NUMBER3_OPERATION] = { | ||
34 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", | ||
35 | [TOMOYO_TYPE_MKCHAR] = "mkchar", | ||
36 | }; | ||
37 | |||
38 | /* Keyword array for operations with two pathnames. */ | ||
42 | static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { | 39 | static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { |
43 | [TOMOYO_TYPE_LINK] = "link", | 40 | [TOMOYO_TYPE_LINK] = "link", |
44 | [TOMOYO_TYPE_RENAME] = "rename", | 41 | [TOMOYO_TYPE_RENAME] = "rename", |
45 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | 42 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", |
46 | }; | 43 | }; |
47 | 44 | ||
45 | /* Keyword array for operations with one pathname and one number. */ | ||
46 | static const char *tomoyo_path_number_keyword | ||
47 | [TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | ||
48 | [TOMOYO_TYPE_CREATE] = "create", | ||
49 | [TOMOYO_TYPE_MKDIR] = "mkdir", | ||
50 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", | ||
51 | [TOMOYO_TYPE_MKSOCK] = "mksock", | ||
52 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
53 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
54 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
55 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
56 | }; | ||
57 | |||
48 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) | 58 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) |
49 | { | 59 | { |
50 | if (!ptr) | 60 | if (!ptr) |
@@ -159,6 +169,19 @@ const char *tomoyo_path2keyword(const u8 operation) | |||
159 | } | 169 | } |
160 | 170 | ||
161 | /** | 171 | /** |
172 | * tomoyo_path_number32keyword - Get the name of path/number/number/number operations. | ||
173 | * | ||
174 | * @operation: Type of operation. | ||
175 | * | ||
176 | * Returns the name of path/number/number/number operation. | ||
177 | */ | ||
178 | const char *tomoyo_path_number32keyword(const u8 operation) | ||
179 | { | ||
180 | return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION) | ||
181 | ? tomoyo_path_number3_keyword[operation] : NULL; | ||
182 | } | ||
183 | |||
184 | /** | ||
162 | * tomoyo_path22keyword - Get the name of double path operation. | 185 | * tomoyo_path22keyword - Get the name of double path operation. |
163 | * | 186 | * |
164 | * @operation: Type of operation. | 187 | * @operation: Type of operation. |
@@ -172,6 +195,19 @@ const char *tomoyo_path22keyword(const u8 operation) | |||
172 | } | 195 | } |
173 | 196 | ||
174 | /** | 197 | /** |
198 | * tomoyo_path_number2keyword - Get the name of path/number operations. | ||
199 | * | ||
200 | * @operation: Type of operation. | ||
201 | * | ||
202 | * Returns the name of path/number operation. | ||
203 | */ | ||
204 | const char *tomoyo_path_number2keyword(const u8 operation) | ||
205 | { | ||
206 | return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION) | ||
207 | ? tomoyo_path_number_keyword[operation] : NULL; | ||
208 | } | ||
209 | |||
210 | /** | ||
175 | * tomoyo_strendswith - Check whether the token ends with the given token. | 211 | * tomoyo_strendswith - Check whether the token ends with the given token. |
176 | * | 212 | * |
177 | * @name: The token to check. | 213 | * @name: The token to check. |
@@ -665,8 +701,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
665 | /** | 701 | /** |
666 | * tomoyo_update_file_acl - Update file's read/write/execute ACL. | 702 | * tomoyo_update_file_acl - Update file's read/write/execute ACL. |
667 | * | 703 | * |
668 | * @filename: Filename. | ||
669 | * @perm: Permission (between 1 to 7). | 704 | * @perm: Permission (between 1 to 7). |
705 | * @filename: Filename. | ||
670 | * @domain: Pointer to "struct tomoyo_domain_info". | 706 | * @domain: Pointer to "struct tomoyo_domain_info". |
671 | * @is_delete: True if it is a delete request. | 707 | * @is_delete: True if it is a delete request. |
672 | * | 708 | * |
@@ -679,7 +715,7 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
679 | * | 715 | * |
680 | * Caller holds tomoyo_read_lock(). | 716 | * Caller holds tomoyo_read_lock(). |
681 | */ | 717 | */ |
682 | static int tomoyo_update_file_acl(const char *filename, u8 perm, | 718 | static int tomoyo_update_file_acl(u8 perm, const char *filename, |
683 | struct tomoyo_domain_info * const domain, | 719 | struct tomoyo_domain_info * const domain, |
684 | const bool is_delete) | 720 | const bool is_delete) |
685 | { | 721 | { |
@@ -731,14 +767,8 @@ static int tomoyo_path_acl(const struct tomoyo_request_info *r, | |||
731 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) | 767 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) |
732 | continue; | 768 | continue; |
733 | acl = container_of(ptr, struct tomoyo_path_acl, head); | 769 | acl = container_of(ptr, struct tomoyo_path_acl, head); |
734 | if (perm <= 0xFFFF) { | 770 | if (!(acl->perm & perm) || |
735 | if (!(acl->perm & perm)) | 771 | !tomoyo_compare_name_union_pattern(filename, &acl->name, |
736 | continue; | ||
737 | } else { | ||
738 | if (!(acl->perm_high & (perm >> 16))) | ||
739 | continue; | ||
740 | } | ||
741 | if (!tomoyo_compare_name_union_pattern(filename, &acl->name, | ||
742 | may_use_pattern)) | 772 | may_use_pattern)) |
743 | continue; | 773 | continue; |
744 | error = 0; | 774 | error = 0; |
@@ -796,61 +826,13 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r, | |||
796 | /* Don't use patterns for execute permission. */ | 826 | /* Don't use patterns for execute permission. */ |
797 | const struct tomoyo_path_info *patterned_file = (mode != 1) ? | 827 | const struct tomoyo_path_info *patterned_file = (mode != 1) ? |
798 | tomoyo_get_file_pattern(filename) : filename; | 828 | tomoyo_get_file_pattern(filename) : filename; |
799 | tomoyo_update_file_acl(patterned_file->name, mode, | 829 | tomoyo_update_file_acl(mode, patterned_file->name, r->domain, |
800 | r->domain, false); | 830 | false); |
801 | } | 831 | } |
802 | return 0; | 832 | return 0; |
803 | } | 833 | } |
804 | 834 | ||
805 | /** | 835 | /** |
806 | * tomoyo_write_file_policy - Update file related list. | ||
807 | * | ||
808 | * @data: String to parse. | ||
809 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
810 | * @is_delete: True if it is a delete request. | ||
811 | * | ||
812 | * Returns 0 on success, negative value otherwise. | ||
813 | * | ||
814 | * Caller holds tomoyo_read_lock(). | ||
815 | */ | ||
816 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | ||
817 | const bool is_delete) | ||
818 | { | ||
819 | char *filename = strchr(data, ' '); | ||
820 | char *filename2; | ||
821 | unsigned int perm; | ||
822 | u8 type; | ||
823 | |||
824 | if (!filename) | ||
825 | return -EINVAL; | ||
826 | *filename++ = '\0'; | ||
827 | if (sscanf(data, "%u", &perm) == 1) | ||
828 | return tomoyo_update_file_acl(filename, (u8) perm, domain, | ||
829 | is_delete); | ||
830 | if (strncmp(data, "allow_", 6)) | ||
831 | goto out; | ||
832 | data += 6; | ||
833 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { | ||
834 | if (strcmp(data, tomoyo_path_keyword[type])) | ||
835 | continue; | ||
836 | return tomoyo_update_path_acl(type, filename, domain, | ||
837 | is_delete); | ||
838 | } | ||
839 | filename2 = strchr(filename, ' '); | ||
840 | if (!filename2) | ||
841 | goto out; | ||
842 | *filename2++ = '\0'; | ||
843 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { | ||
844 | if (strcmp(data, tomoyo_path2_keyword[type])) | ||
845 | continue; | ||
846 | return tomoyo_update_path2_acl(type, filename, filename2, | ||
847 | domain, is_delete); | ||
848 | } | ||
849 | out: | ||
850 | return -EINVAL; | ||
851 | } | ||
852 | |||
853 | /** | ||
854 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. | 836 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
855 | * | 837 | * |
856 | * @type: Type of operation. | 838 | * @type: Type of operation. |
@@ -866,13 +848,12 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, | |||
866 | struct tomoyo_domain_info *const domain, | 848 | struct tomoyo_domain_info *const domain, |
867 | const bool is_delete) | 849 | const bool is_delete) |
868 | { | 850 | { |
869 | static const u32 tomoyo_rw_mask = | 851 | static const u16 tomoyo_rw_mask = |
870 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); | 852 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); |
871 | const u32 perm = 1 << type; | 853 | const u16 perm = 1 << type; |
872 | struct tomoyo_acl_info *ptr; | 854 | struct tomoyo_acl_info *ptr; |
873 | struct tomoyo_path_acl e = { | 855 | struct tomoyo_path_acl e = { |
874 | .head.type = TOMOYO_TYPE_PATH_ACL, | 856 | .head.type = TOMOYO_TYPE_PATH_ACL, |
875 | .perm_high = perm >> 16, | ||
876 | .perm = perm | 857 | .perm = perm |
877 | }; | 858 | }; |
878 | int error = is_delete ? -ENOENT : -ENOMEM; | 859 | int error = is_delete ? -ENOENT : -ENOMEM; |
@@ -891,19 +872,13 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, | |||
891 | if (!tomoyo_is_same_path_acl(acl, &e)) | 872 | if (!tomoyo_is_same_path_acl(acl, &e)) |
892 | continue; | 873 | continue; |
893 | if (is_delete) { | 874 | if (is_delete) { |
894 | if (perm <= 0xFFFF) | 875 | acl->perm &= ~perm; |
895 | acl->perm &= ~perm; | ||
896 | else | ||
897 | acl->perm_high &= ~(perm >> 16); | ||
898 | if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) | 876 | if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) |
899 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); | 877 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); |
900 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) | 878 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
901 | acl->perm &= ~tomoyo_rw_mask; | 879 | acl->perm &= ~tomoyo_rw_mask; |
902 | } else { | 880 | } else { |
903 | if (perm <= 0xFFFF) | 881 | acl->perm |= perm; |
904 | acl->perm |= perm; | ||
905 | else | ||
906 | acl->perm_high |= (perm >> 16); | ||
907 | if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) | 882 | if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) |
908 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; | 883 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; |
909 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) | 884 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) |
@@ -928,6 +903,71 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, | |||
928 | } | 903 | } |
929 | 904 | ||
930 | /** | 905 | /** |
906 | * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. | ||
907 | * | ||
908 | * @type: Type of operation. | ||
909 | * @filename: Filename. | ||
910 | * @mode: Create mode. | ||
911 | * @major: Device major number. | ||
912 | * @minor: Device minor number. | ||
913 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
914 | * @is_delete: True if it is a delete request. | ||
915 | * | ||
916 | * Returns 0 on success, negative value otherwise. | ||
917 | */ | ||
918 | static inline int tomoyo_update_path_number3_acl(const u8 type, | ||
919 | const char *filename, | ||
920 | char *mode, | ||
921 | char *major, char *minor, | ||
922 | struct tomoyo_domain_info * | ||
923 | const domain, | ||
924 | const bool is_delete) | ||
925 | { | ||
926 | const u8 perm = 1 << type; | ||
927 | struct tomoyo_acl_info *ptr; | ||
928 | struct tomoyo_path_number3_acl e = { | ||
929 | .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, | ||
930 | .perm = perm | ||
931 | }; | ||
932 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
933 | if (!tomoyo_parse_name_union(filename, &e.name) || | ||
934 | !tomoyo_parse_number_union(mode, &e.mode) || | ||
935 | !tomoyo_parse_number_union(major, &e.major) || | ||
936 | !tomoyo_parse_number_union(minor, &e.minor)) | ||
937 | goto out; | ||
938 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
939 | goto out; | ||
940 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
941 | struct tomoyo_path_number3_acl *acl = | ||
942 | container_of(ptr, struct tomoyo_path_number3_acl, head); | ||
943 | if (!tomoyo_is_same_path_number3_acl(acl, &e)) | ||
944 | continue; | ||
945 | if (is_delete) | ||
946 | acl->perm &= ~perm; | ||
947 | else | ||
948 | acl->perm |= perm; | ||
949 | error = 0; | ||
950 | break; | ||
951 | } | ||
952 | if (!is_delete && error) { | ||
953 | struct tomoyo_path_number3_acl *entry = | ||
954 | tomoyo_commit_ok(&e, sizeof(e)); | ||
955 | if (entry) { | ||
956 | list_add_tail_rcu(&entry->head.list, | ||
957 | &domain->acl_info_list); | ||
958 | error = 0; | ||
959 | } | ||
960 | } | ||
961 | mutex_unlock(&tomoyo_policy_lock); | ||
962 | out: | ||
963 | tomoyo_put_name_union(&e.name); | ||
964 | tomoyo_put_number_union(&e.mode); | ||
965 | tomoyo_put_number_union(&e.major); | ||
966 | tomoyo_put_number_union(&e.minor); | ||
967 | return error; | ||
968 | } | ||
969 | |||
970 | /** | ||
931 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. | 971 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
932 | * | 972 | * |
933 | * @type: Type of operation. | 973 | * @type: Type of operation. |
@@ -989,6 +1029,50 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1, | |||
989 | } | 1029 | } |
990 | 1030 | ||
991 | /** | 1031 | /** |
1032 | * tomoyo_path_number3_acl - Check permission for path/number/number/number operation. | ||
1033 | * | ||
1034 | * @r: Pointer to "struct tomoyo_request_info". | ||
1035 | * @filename: Filename to check. | ||
1036 | * @perm: Permission. | ||
1037 | * @mode: Create mode. | ||
1038 | * @major: Device major number. | ||
1039 | * @minor: Device minor number. | ||
1040 | * | ||
1041 | * Returns 0 on success, -EPERM otherwise. | ||
1042 | * | ||
1043 | * Caller holds tomoyo_read_lock(). | ||
1044 | */ | ||
1045 | static int tomoyo_path_number3_acl(struct tomoyo_request_info *r, | ||
1046 | const struct tomoyo_path_info *filename, | ||
1047 | const u16 perm, const unsigned int mode, | ||
1048 | const unsigned int major, | ||
1049 | const unsigned int minor) | ||
1050 | { | ||
1051 | struct tomoyo_domain_info *domain = r->domain; | ||
1052 | struct tomoyo_acl_info *ptr; | ||
1053 | int error = -EPERM; | ||
1054 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
1055 | struct tomoyo_path_number3_acl *acl; | ||
1056 | if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL) | ||
1057 | continue; | ||
1058 | acl = container_of(ptr, struct tomoyo_path_number3_acl, head); | ||
1059 | if (!tomoyo_compare_number_union(mode, &acl->mode)) | ||
1060 | continue; | ||
1061 | if (!tomoyo_compare_number_union(major, &acl->major)) | ||
1062 | continue; | ||
1063 | if (!tomoyo_compare_number_union(minor, &acl->minor)) | ||
1064 | continue; | ||
1065 | if (!(acl->perm & perm)) | ||
1066 | continue; | ||
1067 | if (!tomoyo_compare_name_union(filename, &acl->name)) | ||
1068 | continue; | ||
1069 | error = 0; | ||
1070 | break; | ||
1071 | } | ||
1072 | return error; | ||
1073 | } | ||
1074 | |||
1075 | /** | ||
992 | * tomoyo_path2_acl - Check permission for double path operation. | 1076 | * tomoyo_path2_acl - Check permission for double path operation. |
993 | * | 1077 | * |
994 | * @r: Pointer to "struct tomoyo_request_info". | 1078 | * @r: Pointer to "struct tomoyo_request_info". |
@@ -1069,6 +1153,195 @@ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
1069 | } | 1153 | } |
1070 | 1154 | ||
1071 | /** | 1155 | /** |
1156 | * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation. | ||
1157 | * | ||
1158 | * @r: Pointer to "struct tomoyo_request_info". | ||
1159 | * @type: Operation. | ||
1160 | * @filename: Filename to check. | ||
1161 | * @number: Number. | ||
1162 | * | ||
1163 | * Returns 0 on success, -EPERM otherwise. | ||
1164 | * | ||
1165 | * Caller holds tomoyo_read_lock(). | ||
1166 | */ | ||
1167 | static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type, | ||
1168 | const struct tomoyo_path_info *filename, | ||
1169 | const unsigned long number) | ||
1170 | { | ||
1171 | struct tomoyo_domain_info *domain = r->domain; | ||
1172 | struct tomoyo_acl_info *ptr; | ||
1173 | const u8 perm = 1 << type; | ||
1174 | int error = -EPERM; | ||
1175 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
1176 | struct tomoyo_path_number_acl *acl; | ||
1177 | if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL) | ||
1178 | continue; | ||
1179 | acl = container_of(ptr, struct tomoyo_path_number_acl, | ||
1180 | head); | ||
1181 | if (!(acl->perm & perm) || | ||
1182 | !tomoyo_compare_number_union(number, &acl->number) || | ||
1183 | !tomoyo_compare_name_union(filename, &acl->name)) | ||
1184 | continue; | ||
1185 | error = 0; | ||
1186 | break; | ||
1187 | } | ||
1188 | return error; | ||
1189 | } | ||
1190 | |||
1191 | /** | ||
1192 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. | ||
1193 | * | ||
1194 | * @type: Type of operation. | ||
1195 | * @filename: Filename. | ||
1196 | * @number: Number. | ||
1197 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1198 | * @is_delete: True if it is a delete request. | ||
1199 | * | ||
1200 | * Returns 0 on success, negative value otherwise. | ||
1201 | */ | ||
1202 | static inline int tomoyo_update_path_number_acl(const u8 type, | ||
1203 | const char *filename, | ||
1204 | char *number, | ||
1205 | struct tomoyo_domain_info * | ||
1206 | const domain, | ||
1207 | const bool is_delete) | ||
1208 | { | ||
1209 | const u8 perm = 1 << type; | ||
1210 | struct tomoyo_acl_info *ptr; | ||
1211 | struct tomoyo_path_number_acl e = { | ||
1212 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, | ||
1213 | .perm = perm | ||
1214 | }; | ||
1215 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
1216 | if (!domain) | ||
1217 | return -EINVAL; | ||
1218 | if (!tomoyo_parse_name_union(filename, &e.name)) | ||
1219 | return -EINVAL; | ||
1220 | if (!tomoyo_parse_number_union(number, &e.number)) | ||
1221 | goto out; | ||
1222 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
1223 | goto out; | ||
1224 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
1225 | struct tomoyo_path_number_acl *acl = | ||
1226 | container_of(ptr, struct tomoyo_path_number_acl, head); | ||
1227 | if (!tomoyo_is_same_path_number_acl(acl, &e)) | ||
1228 | continue; | ||
1229 | if (is_delete) | ||
1230 | acl->perm &= ~perm; | ||
1231 | else | ||
1232 | acl->perm |= perm; | ||
1233 | error = 0; | ||
1234 | break; | ||
1235 | } | ||
1236 | if (!is_delete && error) { | ||
1237 | struct tomoyo_path_number_acl *entry = | ||
1238 | tomoyo_commit_ok(&e, sizeof(e)); | ||
1239 | if (entry) { | ||
1240 | list_add_tail_rcu(&entry->head.list, | ||
1241 | &domain->acl_info_list); | ||
1242 | error = 0; | ||
1243 | } | ||
1244 | } | ||
1245 | mutex_unlock(&tomoyo_policy_lock); | ||
1246 | out: | ||
1247 | tomoyo_put_name_union(&e.name); | ||
1248 | tomoyo_put_number_union(&e.number); | ||
1249 | return error; | ||
1250 | } | ||
1251 | |||
1252 | /** | ||
1253 | * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". | ||
1254 | * | ||
1255 | * @r: Pointer to "strct tomoyo_request_info". | ||
1256 | * @filename: Filename to check. | ||
1257 | * @number: Number. | ||
1258 | * | ||
1259 | * Returns 0 on success, negative value otherwise. | ||
1260 | * | ||
1261 | * Caller holds tomoyo_read_lock(). | ||
1262 | */ | ||
1263 | static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, | ||
1264 | const u8 type, | ||
1265 | const struct tomoyo_path_info *filename, | ||
1266 | const unsigned long number) | ||
1267 | { | ||
1268 | char buffer[64]; | ||
1269 | int error; | ||
1270 | u8 radix; | ||
1271 | |||
1272 | if (!filename) | ||
1273 | return 0; | ||
1274 | switch (type) { | ||
1275 | case TOMOYO_TYPE_CREATE: | ||
1276 | case TOMOYO_TYPE_MKDIR: | ||
1277 | case TOMOYO_TYPE_MKFIFO: | ||
1278 | case TOMOYO_TYPE_MKSOCK: | ||
1279 | case TOMOYO_TYPE_CHMOD: | ||
1280 | radix = TOMOYO_VALUE_TYPE_OCTAL; | ||
1281 | break; | ||
1282 | case TOMOYO_TYPE_IOCTL: | ||
1283 | radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; | ||
1284 | break; | ||
1285 | default: | ||
1286 | radix = TOMOYO_VALUE_TYPE_DECIMAL; | ||
1287 | break; | ||
1288 | } | ||
1289 | tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); | ||
1290 | error = tomoyo_path_number_acl(r, type, filename, number); | ||
1291 | if (!error) | ||
1292 | return 0; | ||
1293 | tomoyo_warn_log(r, "%s %s %s", tomoyo_path_number2keyword(type), | ||
1294 | filename->name, buffer); | ||
1295 | if (tomoyo_domain_quota_is_ok(r)) | ||
1296 | tomoyo_update_path_number_acl(type, | ||
1297 | tomoyo_get_file_pattern(filename) | ||
1298 | ->name, buffer, r->domain, false); | ||
1299 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
1300 | error = 0; | ||
1301 | return error; | ||
1302 | } | ||
1303 | |||
1304 | /** | ||
1305 | * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". | ||
1306 | * | ||
1307 | * @type: Type of operation. | ||
1308 | * @path: Pointer to "struct path". | ||
1309 | * @number: Number. | ||
1310 | * | ||
1311 | * Returns 0 on success, negative value otherwise. | ||
1312 | */ | ||
1313 | int tomoyo_path_number_perm(const u8 type, struct path *path, | ||
1314 | unsigned long number) | ||
1315 | { | ||
1316 | struct tomoyo_request_info r; | ||
1317 | int error = -ENOMEM; | ||
1318 | struct tomoyo_path_info *buf; | ||
1319 | int idx; | ||
1320 | |||
1321 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || | ||
1322 | !path->mnt || !path->dentry) | ||
1323 | return 0; | ||
1324 | idx = tomoyo_read_lock(); | ||
1325 | buf = tomoyo_get_path(path); | ||
1326 | if (!buf) | ||
1327 | goto out; | ||
1328 | if (type == TOMOYO_TYPE_MKDIR && !buf->is_dir) { | ||
1329 | /* | ||
1330 | * tomoyo_get_path() reserves space for appending "/." | ||
1331 | */ | ||
1332 | strcat((char *) buf->name, "/"); | ||
1333 | tomoyo_fill_path_info(buf); | ||
1334 | } | ||
1335 | error = tomoyo_path_number_perm2(&r, type, buf, number); | ||
1336 | out: | ||
1337 | kfree(buf); | ||
1338 | tomoyo_read_unlock(idx); | ||
1339 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | ||
1340 | error = 0; | ||
1341 | return error; | ||
1342 | } | ||
1343 | |||
1344 | /** | ||
1072 | * tomoyo_check_exec_perm - Check permission for "execute". | 1345 | * tomoyo_check_exec_perm - Check permission for "execute". |
1073 | * | 1346 | * |
1074 | * @domain: Pointer to "struct tomoyo_domain_info". | 1347 | * @domain: Pointer to "struct tomoyo_domain_info". |
@@ -1145,7 +1418,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1145 | } | 1418 | } |
1146 | 1419 | ||
1147 | /** | 1420 | /** |
1148 | * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "rewrite", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". | 1421 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot", "mount" and "unmount". |
1149 | * | 1422 | * |
1150 | * @operation: Type of operation. | 1423 | * @operation: Type of operation. |
1151 | * @path: Pointer to "struct path". | 1424 | * @path: Pointer to "struct path". |
@@ -1173,7 +1446,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path) | |||
1173 | goto out; | 1446 | goto out; |
1174 | } | 1447 | } |
1175 | break; | 1448 | break; |
1176 | case TOMOYO_TYPE_MKDIR: | ||
1177 | case TOMOYO_TYPE_RMDIR: | 1449 | case TOMOYO_TYPE_RMDIR: |
1178 | case TOMOYO_TYPE_CHROOT: | 1450 | case TOMOYO_TYPE_CHROOT: |
1179 | if (!buf->is_dir) { | 1451 | if (!buf->is_dir) { |
@@ -1194,6 +1466,91 @@ int tomoyo_path_perm(const u8 operation, struct path *path) | |||
1194 | } | 1466 | } |
1195 | 1467 | ||
1196 | /** | 1468 | /** |
1469 | * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation. | ||
1470 | * | ||
1471 | * @r: Pointer to "struct tomoyo_request_info". | ||
1472 | * @operation: Type of operation. | ||
1473 | * @filename: Filename to check. | ||
1474 | * @mode: Create mode. | ||
1475 | * @dev: Device number. | ||
1476 | * | ||
1477 | * Returns 0 on success, negative value otherwise. | ||
1478 | * | ||
1479 | * Caller holds tomoyo_read_lock(). | ||
1480 | */ | ||
1481 | static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, | ||
1482 | const u8 operation, | ||
1483 | const struct tomoyo_path_info *filename, | ||
1484 | const unsigned int mode, | ||
1485 | const unsigned int dev) | ||
1486 | { | ||
1487 | int error; | ||
1488 | const unsigned int major = MAJOR(dev); | ||
1489 | const unsigned int minor = MINOR(dev); | ||
1490 | |||
1491 | error = tomoyo_path_number3_acl(r, filename, 1 << operation, mode, | ||
1492 | major, minor); | ||
1493 | if (!error) | ||
1494 | return 0; | ||
1495 | tomoyo_warn_log(r, "%s %s 0%o %u %u", | ||
1496 | tomoyo_path_number32keyword(operation), | ||
1497 | filename->name, mode, major, minor); | ||
1498 | if (tomoyo_domain_quota_is_ok(r)) { | ||
1499 | char mode_buf[64]; | ||
1500 | char major_buf[64]; | ||
1501 | char minor_buf[64]; | ||
1502 | memset(mode_buf, 0, sizeof(mode_buf)); | ||
1503 | memset(major_buf, 0, sizeof(major_buf)); | ||
1504 | memset(minor_buf, 0, sizeof(minor_buf)); | ||
1505 | snprintf(mode_buf, sizeof(mode_buf) - 1, "0%o", mode); | ||
1506 | snprintf(major_buf, sizeof(major_buf) - 1, "%u", major); | ||
1507 | snprintf(minor_buf, sizeof(minor_buf) - 1, "%u", minor); | ||
1508 | tomoyo_update_path_number3_acl(operation, | ||
1509 | tomoyo_get_file_pattern(filename) | ||
1510 | ->name, mode_buf, major_buf, | ||
1511 | minor_buf, r->domain, false); | ||
1512 | } | ||
1513 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
1514 | error = 0; | ||
1515 | return error; | ||
1516 | } | ||
1517 | |||
1518 | /** | ||
1519 | * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar". | ||
1520 | * | ||
1521 | * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) | ||
1522 | * @path: Pointer to "struct path". | ||
1523 | * @mode: Create mode. | ||
1524 | * @dev: Device number. | ||
1525 | * | ||
1526 | * Returns 0 on success, negative value otherwise. | ||
1527 | */ | ||
1528 | int tomoyo_path_number3_perm(const u8 operation, struct path *path, | ||
1529 | const unsigned int mode, unsigned int dev) | ||
1530 | { | ||
1531 | struct tomoyo_request_info r; | ||
1532 | int error = -ENOMEM; | ||
1533 | struct tomoyo_path_info *buf; | ||
1534 | int idx; | ||
1535 | |||
1536 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || | ||
1537 | !path->mnt) | ||
1538 | return 0; | ||
1539 | idx = tomoyo_read_lock(); | ||
1540 | error = -ENOMEM; | ||
1541 | buf = tomoyo_get_path(path); | ||
1542 | if (buf) { | ||
1543 | error = tomoyo_path_number3_perm2(&r, operation, buf, mode, | ||
1544 | new_decode_dev(dev)); | ||
1545 | kfree(buf); | ||
1546 | } | ||
1547 | tomoyo_read_unlock(idx); | ||
1548 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | ||
1549 | error = 0; | ||
1550 | return error; | ||
1551 | } | ||
1552 | |||
1553 | /** | ||
1197 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". | 1554 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". |
1198 | * | 1555 | * |
1199 | * @operation: Type of operation. | 1556 | * @operation: Type of operation. |
@@ -1254,3 +1611,60 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1254 | error = 0; | 1611 | error = 0; |
1255 | return error; | 1612 | return error; |
1256 | } | 1613 | } |
1614 | |||
1615 | /** | ||
1616 | * tomoyo_write_file_policy - Update file related list. | ||
1617 | * | ||
1618 | * @data: String to parse. | ||
1619 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1620 | * @is_delete: True if it is a delete request. | ||
1621 | * | ||
1622 | * Returns 0 on success, negative value otherwise. | ||
1623 | * | ||
1624 | * Caller holds tomoyo_read_lock(). | ||
1625 | */ | ||
1626 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | ||
1627 | const bool is_delete) | ||
1628 | { | ||
1629 | char *w[5]; | ||
1630 | u8 type; | ||
1631 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) | ||
1632 | return -EINVAL; | ||
1633 | if (strncmp(w[0], "allow_", 6)) { | ||
1634 | unsigned int perm; | ||
1635 | if (sscanf(w[0], "%u", &perm) == 1) | ||
1636 | return tomoyo_update_file_acl((u8) perm, w[1], domain, | ||
1637 | is_delete); | ||
1638 | goto out; | ||
1639 | } | ||
1640 | w[0] += 6; | ||
1641 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { | ||
1642 | if (strcmp(w[0], tomoyo_path_keyword[type])) | ||
1643 | continue; | ||
1644 | return tomoyo_update_path_acl(type, w[1], domain, is_delete); | ||
1645 | } | ||
1646 | if (!w[2][0]) | ||
1647 | goto out; | ||
1648 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { | ||
1649 | if (strcmp(w[0], tomoyo_path2_keyword[type])) | ||
1650 | continue; | ||
1651 | return tomoyo_update_path2_acl(type, w[1], w[2], domain, | ||
1652 | is_delete); | ||
1653 | } | ||
1654 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { | ||
1655 | if (strcmp(w[0], tomoyo_path_number_keyword[type])) | ||
1656 | continue; | ||
1657 | return tomoyo_update_path_number_acl(type, w[1], w[2], domain, | ||
1658 | is_delete); | ||
1659 | } | ||
1660 | if (!w[3][0] || !w[4][0]) | ||
1661 | goto out; | ||
1662 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) { | ||
1663 | if (strcmp(w[0], tomoyo_path_number3_keyword[type])) | ||
1664 | continue; | ||
1665 | return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3], | ||
1666 | w[4], domain, is_delete); | ||
1667 | } | ||
1668 | out: | ||
1669 | return -EINVAL; | ||
1670 | } | ||