diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
-rw-r--r-- | security/tomoyo/common.c | 374 | ||||
-rw-r--r-- | security/tomoyo/common.h | 530 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 391 | ||||
-rw-r--r-- | security/tomoyo/file.c | 731 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 370 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 269 | ||||
-rw-r--r-- | security/tomoyo/realpath.h | 66 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 142 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.h | 94 |
10 files changed, 1598 insertions, 1371 deletions
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 10ccd686b290..60a9e2002da1 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1 +1 @@ | |||
obj-y = common.o realpath.o tomoyo.o domain.o file.o | obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index e0d0354008b7..ff51f1026b57 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -12,9 +12,10 @@ | |||
12 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
13 | #include <linux/security.h> | 13 | #include <linux/security.h> |
14 | #include <linux/hardirq.h> | 14 | #include <linux/hardirq.h> |
15 | #include "realpath.h" | ||
16 | #include "common.h" | 15 | #include "common.h" |
17 | #include "tomoyo.h" | 16 | |
17 | /* Lock for protecting policy. */ | ||
18 | DEFINE_MUTEX(tomoyo_policy_lock); | ||
18 | 19 | ||
19 | /* Has loading policy done? */ | 20 | /* Has loading policy done? */ |
20 | bool tomoyo_policy_loaded; | 21 | bool tomoyo_policy_loaded; |
@@ -178,14 +179,12 @@ static void tomoyo_normalize_line(unsigned char *buffer) | |||
178 | * 1 = must / -1 = must not / 0 = don't care | 179 | * 1 = must / -1 = must not / 0 = don't care |
179 | * @end_type: Should the pathname end with '/'? | 180 | * @end_type: Should the pathname end with '/'? |
180 | * 1 = must / -1 = must not / 0 = don't care | 181 | * 1 = must / -1 = must not / 0 = don't care |
181 | * @function: The name of function calling me. | ||
182 | * | 182 | * |
183 | * Check whether the given filename follows the naming rules. | 183 | * Check whether the given filename follows the naming rules. |
184 | * Returns true if @filename follows the naming rules, false otherwise. | 184 | * Returns true if @filename follows the naming rules, false otherwise. |
185 | */ | 185 | */ |
186 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | 186 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, |
187 | const s8 pattern_type, const s8 end_type, | 187 | const s8 pattern_type, const s8 end_type) |
188 | const char *function) | ||
189 | { | 188 | { |
190 | const char *const start = filename; | 189 | const char *const start = filename; |
191 | bool in_repetition = false; | 190 | bool in_repetition = false; |
@@ -193,7 +192,6 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
193 | unsigned char c; | 192 | unsigned char c; |
194 | unsigned char d; | 193 | unsigned char d; |
195 | unsigned char e; | 194 | unsigned char e; |
196 | const char *original_filename = filename; | ||
197 | 195 | ||
198 | if (!filename) | 196 | if (!filename) |
199 | goto out; | 197 | goto out; |
@@ -282,25 +280,20 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
282 | goto out; | 280 | goto out; |
283 | return true; | 281 | return true; |
284 | out: | 282 | out: |
285 | printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, | ||
286 | original_filename); | ||
287 | return false; | 283 | return false; |
288 | } | 284 | } |
289 | 285 | ||
290 | /** | 286 | /** |
291 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. | 287 | * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. |
292 | * @domainname: The domainname to check. | 288 | * @domainname: The domainname to check. |
293 | * @function: The name of function calling me. | ||
294 | * | 289 | * |
295 | * Returns true if @domainname follows the naming rules, false otherwise. | 290 | * Returns true if @domainname follows the naming rules, false otherwise. |
296 | */ | 291 | */ |
297 | bool tomoyo_is_correct_domain(const unsigned char *domainname, | 292 | bool tomoyo_is_correct_domain(const unsigned char *domainname) |
298 | const char *function) | ||
299 | { | 293 | { |
300 | unsigned char c; | 294 | unsigned char c; |
301 | unsigned char d; | 295 | unsigned char d; |
302 | unsigned char e; | 296 | unsigned char e; |
303 | const char *org_domainname = domainname; | ||
304 | 297 | ||
305 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, | 298 | if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, |
306 | TOMOYO_ROOT_NAME_LEN)) | 299 | TOMOYO_ROOT_NAME_LEN)) |
@@ -343,8 +336,6 @@ bool tomoyo_is_correct_domain(const unsigned char *domainname, | |||
343 | } while (*domainname); | 336 | } while (*domainname); |
344 | return true; | 337 | return true; |
345 | out: | 338 | out: |
346 | printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, | ||
347 | org_domainname); | ||
348 | return false; | 339 | return false; |
349 | } | 340 | } |
350 | 341 | ||
@@ -365,10 +356,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer) | |||
365 | * | 356 | * |
366 | * @domainname: The domainname to find. | 357 | * @domainname: The domainname to find. |
367 | * | 358 | * |
368 | * Caller must call down_read(&tomoyo_domain_list_lock); or | ||
369 | * down_write(&tomoyo_domain_list_lock); . | ||
370 | * | ||
371 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. | 359 | * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. |
360 | * | ||
361 | * Caller holds tomoyo_read_lock(). | ||
372 | */ | 362 | */ |
373 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | 363 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) |
374 | { | 364 | { |
@@ -377,7 +367,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) | |||
377 | 367 | ||
378 | name.name = domainname; | 368 | name.name = domainname; |
379 | tomoyo_fill_path_info(&name); | 369 | tomoyo_fill_path_info(&name); |
380 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 370 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
381 | if (!domain->is_deleted && | 371 | if (!domain->is_deleted && |
382 | !tomoyo_pathcmp(&name, domain->domainname)) | 372 | !tomoyo_pathcmp(&name, domain->domainname)) |
383 | return domain; | 373 | return domain; |
@@ -748,7 +738,7 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | |||
748 | * | 738 | * |
749 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. | 739 | * Returns the tomoyo_realpath() of current process on success, NULL otherwise. |
750 | * | 740 | * |
751 | * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() | 741 | * This function uses kzalloc(), so the caller must call kfree() |
752 | * if this function didn't return NULL. | 742 | * if this function didn't return NULL. |
753 | */ | 743 | */ |
754 | static const char *tomoyo_get_exe(void) | 744 | static const char *tomoyo_get_exe(void) |
@@ -829,6 +819,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) | |||
829 | * @domain: Pointer to "struct tomoyo_domain_info". | 819 | * @domain: Pointer to "struct tomoyo_domain_info". |
830 | * | 820 | * |
831 | * Returns true if the domain is not exceeded quota, false otherwise. | 821 | * Returns true if the domain is not exceeded quota, false otherwise. |
822 | * | ||
823 | * Caller holds tomoyo_read_lock(). | ||
832 | */ | 824 | */ |
833 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | 825 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) |
834 | { | 826 | { |
@@ -837,61 +829,29 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | |||
837 | 829 | ||
838 | if (!domain) | 830 | if (!domain) |
839 | return true; | 831 | return true; |
840 | down_read(&tomoyo_domain_acl_info_list_lock); | 832 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
841 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 833 | switch (ptr->type) { |
842 | if (ptr->type & TOMOYO_ACL_DELETED) | 834 | struct tomoyo_path_acl *acl; |
843 | continue; | 835 | u32 perm; |
844 | switch (tomoyo_acl_type2(ptr)) { | 836 | u8 i; |
845 | struct tomoyo_single_path_acl_record *acl1; | 837 | case TOMOYO_TYPE_PATH_ACL: |
846 | struct tomoyo_double_path_acl_record *acl2; | 838 | acl = container_of(ptr, struct tomoyo_path_acl, head); |
847 | u16 perm; | 839 | perm = acl->perm | (((u32) acl->perm_high) << 16); |
848 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | 840 | for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) |
849 | acl1 = container_of(ptr, | 841 | if (perm & (1 << i)) |
850 | struct tomoyo_single_path_acl_record, | 842 | count++; |
851 | head); | 843 | if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) |
852 | perm = acl1->perm; | 844 | count -= 2; |
853 | if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL)) | ||
854 | count++; | ||
855 | if (perm & | ||
856 | ((1 << TOMOYO_TYPE_READ_ACL) | | ||
857 | (1 << TOMOYO_TYPE_WRITE_ACL))) | ||
858 | count++; | ||
859 | if (perm & (1 << TOMOYO_TYPE_CREATE_ACL)) | ||
860 | count++; | ||
861 | if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL)) | ||
862 | count++; | ||
863 | if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL)) | ||
864 | count++; | ||
865 | if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL)) | ||
866 | count++; | ||
867 | if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL)) | ||
868 | count++; | ||
869 | if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL)) | ||
870 | count++; | ||
871 | if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL)) | ||
872 | count++; | ||
873 | if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL)) | ||
874 | count++; | ||
875 | if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL)) | ||
876 | count++; | ||
877 | if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL)) | ||
878 | count++; | ||
879 | if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL)) | ||
880 | count++; | ||
881 | break; | 845 | break; |
882 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | 846 | case TOMOYO_TYPE_PATH2_ACL: |
883 | acl2 = container_of(ptr, | 847 | perm = container_of(ptr, struct tomoyo_path2_acl, head) |
884 | struct tomoyo_double_path_acl_record, | 848 | ->perm; |
885 | head); | 849 | for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) |
886 | perm = acl2->perm; | 850 | if (perm & (1 << i)) |
887 | if (perm & (1 << TOMOYO_TYPE_LINK_ACL)) | 851 | count++; |
888 | count++; | ||
889 | if (perm & (1 << TOMOYO_TYPE_RENAME_ACL)) | ||
890 | count++; | ||
891 | break; | 852 | break; |
892 | } | 853 | } |
893 | } | 854 | } |
894 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
895 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) | 855 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) |
896 | return true; | 856 | return true; |
897 | if (!domain->quota_warned) { | 857 | if (!domain->quota_warned) { |
@@ -923,9 +883,11 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
923 | ptr = tomoyo_profile_ptr[profile]; | 883 | ptr = tomoyo_profile_ptr[profile]; |
924 | if (ptr) | 884 | if (ptr) |
925 | goto ok; | 885 | goto ok; |
926 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | 886 | ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); |
927 | if (!ptr) | 887 | if (!tomoyo_memory_ok(ptr)) { |
888 | kfree(ptr); | ||
928 | goto ok; | 889 | goto ok; |
890 | } | ||
929 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) | 891 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) |
930 | ptr->value[i] = tomoyo_control_array[i].current_value; | 892 | ptr->value[i] = tomoyo_control_array[i].current_value; |
931 | mb(); /* Avoid out-of-order execution. */ | 893 | mb(); /* Avoid out-of-order execution. */ |
@@ -966,7 +928,9 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) | |||
966 | return -EINVAL; | 928 | return -EINVAL; |
967 | *cp = '\0'; | 929 | *cp = '\0'; |
968 | if (!strcmp(data, "COMMENT")) { | 930 | if (!strcmp(data, "COMMENT")) { |
969 | profile->comment = tomoyo_save_name(cp + 1); | 931 | const struct tomoyo_path_info *old_comment = profile->comment; |
932 | profile->comment = tomoyo_get_name(cp + 1); | ||
933 | tomoyo_put_name(old_comment); | ||
970 | return 0; | 934 | return 0; |
971 | } | 935 | } |
972 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { | 936 | for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { |
@@ -1061,27 +1025,6 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
1061 | } | 1025 | } |
1062 | 1026 | ||
1063 | /* | 1027 | /* |
1064 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
1065 | * domainnames or programs which are permitted to modify configuration via | ||
1066 | * /sys/kernel/security/tomoyo/ interface. | ||
1067 | * It has following fields. | ||
1068 | * | ||
1069 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
1070 | * (2) "manager" is a domainname or a program's pathname. | ||
1071 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
1072 | * otherwise. | ||
1073 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
1074 | * otherwise. | ||
1075 | */ | ||
1076 | struct tomoyo_policy_manager_entry { | ||
1077 | struct list_head list; | ||
1078 | /* A path to program or a domainname. */ | ||
1079 | const struct tomoyo_path_info *manager; | ||
1080 | bool is_domain; /* True if manager is a domainname. */ | ||
1081 | bool is_deleted; /* True if this entry is deleted. */ | ||
1082 | }; | ||
1083 | |||
1084 | /* | ||
1085 | * tomoyo_policy_manager_list is used for holding list of domainnames or | 1028 | * tomoyo_policy_manager_list is used for holding list of domainnames or |
1086 | * programs which are permitted to modify configuration via | 1029 | * programs which are permitted to modify configuration via |
1087 | * /sys/kernel/security/tomoyo/ interface. | 1030 | * /sys/kernel/security/tomoyo/ interface. |
@@ -1111,8 +1054,7 @@ struct tomoyo_policy_manager_entry { | |||
1111 | * | 1054 | * |
1112 | * # cat /sys/kernel/security/tomoyo/manager | 1055 | * # cat /sys/kernel/security/tomoyo/manager |
1113 | */ | 1056 | */ |
1114 | static LIST_HEAD(tomoyo_policy_manager_list); | 1057 | LIST_HEAD(tomoyo_policy_manager_list); |
1115 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | ||
1116 | 1058 | ||
1117 | /** | 1059 | /** |
1118 | * tomoyo_update_manager_entry - Add a manager entry. | 1060 | * tomoyo_update_manager_entry - Add a manager entry. |
@@ -1121,48 +1063,50 @@ static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | |||
1121 | * @is_delete: True if it is a delete request. | 1063 | * @is_delete: True if it is a delete request. |
1122 | * | 1064 | * |
1123 | * Returns 0 on success, negative value otherwise. | 1065 | * Returns 0 on success, negative value otherwise. |
1066 | * | ||
1067 | * Caller holds tomoyo_read_lock(). | ||
1124 | */ | 1068 | */ |
1125 | static int tomoyo_update_manager_entry(const char *manager, | 1069 | static int tomoyo_update_manager_entry(const char *manager, |
1126 | const bool is_delete) | 1070 | const bool is_delete) |
1127 | { | 1071 | { |
1128 | struct tomoyo_policy_manager_entry *new_entry; | 1072 | struct tomoyo_policy_manager_entry *entry = NULL; |
1129 | struct tomoyo_policy_manager_entry *ptr; | 1073 | struct tomoyo_policy_manager_entry *ptr; |
1130 | const struct tomoyo_path_info *saved_manager; | 1074 | const struct tomoyo_path_info *saved_manager; |
1131 | int error = -ENOMEM; | 1075 | int error = is_delete ? -ENOENT : -ENOMEM; |
1132 | bool is_domain = false; | 1076 | bool is_domain = false; |
1133 | 1077 | ||
1134 | if (tomoyo_is_domain_def(manager)) { | 1078 | if (tomoyo_is_domain_def(manager)) { |
1135 | if (!tomoyo_is_correct_domain(manager, __func__)) | 1079 | if (!tomoyo_is_correct_domain(manager)) |
1136 | return -EINVAL; | 1080 | return -EINVAL; |
1137 | is_domain = true; | 1081 | is_domain = true; |
1138 | } else { | 1082 | } else { |
1139 | if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__)) | 1083 | if (!tomoyo_is_correct_path(manager, 1, -1, -1)) |
1140 | return -EINVAL; | 1084 | return -EINVAL; |
1141 | } | 1085 | } |
1142 | saved_manager = tomoyo_save_name(manager); | 1086 | saved_manager = tomoyo_get_name(manager); |
1143 | if (!saved_manager) | 1087 | if (!saved_manager) |
1144 | return -ENOMEM; | 1088 | return -ENOMEM; |
1145 | down_write(&tomoyo_policy_manager_list_lock); | 1089 | if (!is_delete) |
1146 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1090 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
1091 | mutex_lock(&tomoyo_policy_lock); | ||
1092 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { | ||
1147 | if (ptr->manager != saved_manager) | 1093 | if (ptr->manager != saved_manager) |
1148 | continue; | 1094 | continue; |
1149 | ptr->is_deleted = is_delete; | 1095 | ptr->is_deleted = is_delete; |
1150 | error = 0; | 1096 | error = 0; |
1151 | goto out; | 1097 | break; |
1152 | } | 1098 | } |
1153 | if (is_delete) { | 1099 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
1154 | error = -ENOENT; | 1100 | entry->manager = saved_manager; |
1155 | goto out; | 1101 | saved_manager = NULL; |
1102 | entry->is_domain = is_domain; | ||
1103 | list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); | ||
1104 | entry = NULL; | ||
1105 | error = 0; | ||
1156 | } | 1106 | } |
1157 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 1107 | mutex_unlock(&tomoyo_policy_lock); |
1158 | if (!new_entry) | 1108 | tomoyo_put_name(saved_manager); |
1159 | goto out; | 1109 | kfree(entry); |
1160 | new_entry->manager = saved_manager; | ||
1161 | new_entry->is_domain = is_domain; | ||
1162 | list_add_tail(&new_entry->list, &tomoyo_policy_manager_list); | ||
1163 | error = 0; | ||
1164 | out: | ||
1165 | up_write(&tomoyo_policy_manager_list_lock); | ||
1166 | return error; | 1110 | return error; |
1167 | } | 1111 | } |
1168 | 1112 | ||
@@ -1172,6 +1116,8 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
1172 | * @head: Pointer to "struct tomoyo_io_buffer". | 1116 | * @head: Pointer to "struct tomoyo_io_buffer". |
1173 | * | 1117 | * |
1174 | * Returns 0 on success, negative value otherwise. | 1118 | * Returns 0 on success, negative value otherwise. |
1119 | * | ||
1120 | * Caller holds tomoyo_read_lock(). | ||
1175 | */ | 1121 | */ |
1176 | static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) | 1122 | static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) |
1177 | { | 1123 | { |
@@ -1191,6 +1137,8 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) | |||
1191 | * @head: Pointer to "struct tomoyo_io_buffer". | 1137 | * @head: Pointer to "struct tomoyo_io_buffer". |
1192 | * | 1138 | * |
1193 | * Returns 0. | 1139 | * Returns 0. |
1140 | * | ||
1141 | * Caller holds tomoyo_read_lock(). | ||
1194 | */ | 1142 | */ |
1195 | static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | 1143 | static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) |
1196 | { | 1144 | { |
@@ -1199,7 +1147,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1199 | 1147 | ||
1200 | if (head->read_eof) | 1148 | if (head->read_eof) |
1201 | return 0; | 1149 | return 0; |
1202 | down_read(&tomoyo_policy_manager_list_lock); | ||
1203 | list_for_each_cookie(pos, head->read_var2, | 1150 | list_for_each_cookie(pos, head->read_var2, |
1204 | &tomoyo_policy_manager_list) { | 1151 | &tomoyo_policy_manager_list) { |
1205 | struct tomoyo_policy_manager_entry *ptr; | 1152 | struct tomoyo_policy_manager_entry *ptr; |
@@ -1211,7 +1158,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1211 | if (!done) | 1158 | if (!done) |
1212 | break; | 1159 | break; |
1213 | } | 1160 | } |
1214 | up_read(&tomoyo_policy_manager_list_lock); | ||
1215 | head->read_eof = done; | 1161 | head->read_eof = done; |
1216 | return 0; | 1162 | return 0; |
1217 | } | 1163 | } |
@@ -1221,6 +1167,8 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1221 | * | 1167 | * |
1222 | * Returns true if the current process is permitted to modify policy | 1168 | * Returns true if the current process is permitted to modify policy |
1223 | * via /sys/kernel/security/tomoyo/ interface. | 1169 | * via /sys/kernel/security/tomoyo/ interface. |
1170 | * | ||
1171 | * Caller holds tomoyo_read_lock(). | ||
1224 | */ | 1172 | */ |
1225 | static bool tomoyo_is_policy_manager(void) | 1173 | static bool tomoyo_is_policy_manager(void) |
1226 | { | 1174 | { |
@@ -1234,29 +1182,25 @@ static bool tomoyo_is_policy_manager(void) | |||
1234 | return true; | 1182 | return true; |
1235 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 1183 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
1236 | return false; | 1184 | return false; |
1237 | down_read(&tomoyo_policy_manager_list_lock); | 1185 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { |
1238 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | ||
1239 | if (!ptr->is_deleted && ptr->is_domain | 1186 | if (!ptr->is_deleted && ptr->is_domain |
1240 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | 1187 | && !tomoyo_pathcmp(domainname, ptr->manager)) { |
1241 | found = true; | 1188 | found = true; |
1242 | break; | 1189 | break; |
1243 | } | 1190 | } |
1244 | } | 1191 | } |
1245 | up_read(&tomoyo_policy_manager_list_lock); | ||
1246 | if (found) | 1192 | if (found) |
1247 | return true; | 1193 | return true; |
1248 | exe = tomoyo_get_exe(); | 1194 | exe = tomoyo_get_exe(); |
1249 | if (!exe) | 1195 | if (!exe) |
1250 | return false; | 1196 | return false; |
1251 | down_read(&tomoyo_policy_manager_list_lock); | 1197 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { |
1252 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | ||
1253 | if (!ptr->is_deleted && !ptr->is_domain | 1198 | if (!ptr->is_deleted && !ptr->is_domain |
1254 | && !strcmp(exe, ptr->manager->name)) { | 1199 | && !strcmp(exe, ptr->manager->name)) { |
1255 | found = true; | 1200 | found = true; |
1256 | break; | 1201 | break; |
1257 | } | 1202 | } |
1258 | } | 1203 | } |
1259 | up_read(&tomoyo_policy_manager_list_lock); | ||
1260 | if (!found) { /* Reduce error messages. */ | 1204 | if (!found) { /* Reduce error messages. */ |
1261 | static pid_t last_pid; | 1205 | static pid_t last_pid; |
1262 | const pid_t pid = current->pid; | 1206 | const pid_t pid = current->pid; |
@@ -1266,7 +1210,7 @@ static bool tomoyo_is_policy_manager(void) | |||
1266 | last_pid = pid; | 1210 | last_pid = pid; |
1267 | } | 1211 | } |
1268 | } | 1212 | } |
1269 | tomoyo_free(exe); | 1213 | kfree(exe); |
1270 | return found; | 1214 | return found; |
1271 | } | 1215 | } |
1272 | 1216 | ||
@@ -1277,6 +1221,8 @@ static bool tomoyo_is_policy_manager(void) | |||
1277 | * @data: String to parse. | 1221 | * @data: String to parse. |
1278 | * | 1222 | * |
1279 | * Returns true on success, false otherwise. | 1223 | * Returns true on success, false otherwise. |
1224 | * | ||
1225 | * Caller holds tomoyo_read_lock(). | ||
1280 | */ | 1226 | */ |
1281 | static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | 1227 | static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, |
1282 | const char *data) | 1228 | const char *data) |
@@ -1286,17 +1232,16 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1286 | 1232 | ||
1287 | if (sscanf(data, "pid=%u", &pid) == 1) { | 1233 | if (sscanf(data, "pid=%u", &pid) == 1) { |
1288 | struct task_struct *p; | 1234 | struct task_struct *p; |
1235 | rcu_read_lock(); | ||
1289 | read_lock(&tasklist_lock); | 1236 | read_lock(&tasklist_lock); |
1290 | p = find_task_by_vpid(pid); | 1237 | p = find_task_by_vpid(pid); |
1291 | if (p) | 1238 | if (p) |
1292 | domain = tomoyo_real_domain(p); | 1239 | domain = tomoyo_real_domain(p); |
1293 | read_unlock(&tasklist_lock); | 1240 | read_unlock(&tasklist_lock); |
1241 | rcu_read_unlock(); | ||
1294 | } else if (!strncmp(data, "domain=", 7)) { | 1242 | } else if (!strncmp(data, "domain=", 7)) { |
1295 | if (tomoyo_is_domain_def(data + 7)) { | 1243 | if (tomoyo_is_domain_def(data + 7)) |
1296 | down_read(&tomoyo_domain_list_lock); | ||
1297 | domain = tomoyo_find_domain(data + 7); | 1244 | domain = tomoyo_find_domain(data + 7); |
1298 | up_read(&tomoyo_domain_list_lock); | ||
1299 | } | ||
1300 | } else | 1245 | } else |
1301 | return false; | 1246 | return false; |
1302 | head->write_var1 = domain; | 1247 | head->write_var1 = domain; |
@@ -1310,13 +1255,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1310 | if (domain) { | 1255 | if (domain) { |
1311 | struct tomoyo_domain_info *d; | 1256 | struct tomoyo_domain_info *d; |
1312 | head->read_var1 = NULL; | 1257 | head->read_var1 = NULL; |
1313 | down_read(&tomoyo_domain_list_lock); | 1258 | list_for_each_entry_rcu(d, &tomoyo_domain_list, list) { |
1314 | list_for_each_entry(d, &tomoyo_domain_list, list) { | ||
1315 | if (d == domain) | 1259 | if (d == domain) |
1316 | break; | 1260 | break; |
1317 | head->read_var1 = &d->list; | 1261 | head->read_var1 = &d->list; |
1318 | } | 1262 | } |
1319 | up_read(&tomoyo_domain_list_lock); | ||
1320 | head->read_var2 = NULL; | 1263 | head->read_var2 = NULL; |
1321 | head->read_bit = 0; | 1264 | head->read_bit = 0; |
1322 | head->read_step = 0; | 1265 | head->read_step = 0; |
@@ -1332,6 +1275,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1332 | * @domainname: The name of domain. | 1275 | * @domainname: The name of domain. |
1333 | * | 1276 | * |
1334 | * Returns 0. | 1277 | * Returns 0. |
1278 | * | ||
1279 | * Caller holds tomoyo_read_lock(). | ||
1335 | */ | 1280 | */ |
1336 | static int tomoyo_delete_domain(char *domainname) | 1281 | static int tomoyo_delete_domain(char *domainname) |
1337 | { | 1282 | { |
@@ -1340,9 +1285,9 @@ static int tomoyo_delete_domain(char *domainname) | |||
1340 | 1285 | ||
1341 | name.name = domainname; | 1286 | name.name = domainname; |
1342 | tomoyo_fill_path_info(&name); | 1287 | tomoyo_fill_path_info(&name); |
1343 | down_write(&tomoyo_domain_list_lock); | 1288 | mutex_lock(&tomoyo_policy_lock); |
1344 | /* Is there an active domain? */ | 1289 | /* Is there an active domain? */ |
1345 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 1290 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
1346 | /* Never delete tomoyo_kernel_domain */ | 1291 | /* Never delete tomoyo_kernel_domain */ |
1347 | if (domain == &tomoyo_kernel_domain) | 1292 | if (domain == &tomoyo_kernel_domain) |
1348 | continue; | 1293 | continue; |
@@ -1352,7 +1297,7 @@ static int tomoyo_delete_domain(char *domainname) | |||
1352 | domain->is_deleted = true; | 1297 | domain->is_deleted = true; |
1353 | break; | 1298 | break; |
1354 | } | 1299 | } |
1355 | up_write(&tomoyo_domain_list_lock); | 1300 | mutex_unlock(&tomoyo_policy_lock); |
1356 | return 0; | 1301 | return 0; |
1357 | } | 1302 | } |
1358 | 1303 | ||
@@ -1362,6 +1307,8 @@ static int tomoyo_delete_domain(char *domainname) | |||
1362 | * @head: Pointer to "struct tomoyo_io_buffer". | 1307 | * @head: Pointer to "struct tomoyo_io_buffer". |
1363 | * | 1308 | * |
1364 | * Returns 0 on success, negative value otherwise. | 1309 | * Returns 0 on success, negative value otherwise. |
1310 | * | ||
1311 | * Caller holds tomoyo_read_lock(). | ||
1365 | */ | 1312 | */ |
1366 | static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | 1313 | static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) |
1367 | { | 1314 | { |
@@ -1384,11 +1331,9 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | |||
1384 | domain = NULL; | 1331 | domain = NULL; |
1385 | if (is_delete) | 1332 | if (is_delete) |
1386 | tomoyo_delete_domain(data); | 1333 | tomoyo_delete_domain(data); |
1387 | else if (is_select) { | 1334 | else if (is_select) |
1388 | down_read(&tomoyo_domain_list_lock); | ||
1389 | domain = tomoyo_find_domain(data); | 1335 | domain = tomoyo_find_domain(data); |
1390 | up_read(&tomoyo_domain_list_lock); | 1336 | else |
1391 | } else | ||
1392 | domain = tomoyo_find_or_assign_new_domain(data, 0); | 1337 | domain = tomoyo_find_or_assign_new_domain(data, 0); |
1393 | head->write_var1 = domain; | 1338 | head->write_var1 = domain; |
1394 | return 0; | 1339 | return 0; |
@@ -1403,43 +1348,39 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | |||
1403 | return 0; | 1348 | return 0; |
1404 | } | 1349 | } |
1405 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { | 1350 | if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { |
1406 | tomoyo_set_domain_flag(domain, is_delete, | 1351 | domain->ignore_global_allow_read = !is_delete; |
1407 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ); | ||
1408 | return 0; | 1352 | return 0; |
1409 | } | 1353 | } |
1410 | return tomoyo_write_file_policy(data, domain, is_delete); | 1354 | return tomoyo_write_file_policy(data, domain, is_delete); |
1411 | } | 1355 | } |
1412 | 1356 | ||
1413 | /** | 1357 | /** |
1414 | * tomoyo_print_single_path_acl - Print a single path ACL entry. | 1358 | * tomoyo_print_path_acl - Print a single path ACL entry. |
1415 | * | 1359 | * |
1416 | * @head: Pointer to "struct tomoyo_io_buffer". | 1360 | * @head: Pointer to "struct tomoyo_io_buffer". |
1417 | * @ptr: Pointer to "struct tomoyo_single_path_acl_record". | 1361 | * @ptr: Pointer to "struct tomoyo_path_acl". |
1418 | * | 1362 | * |
1419 | * Returns true on success, false otherwise. | 1363 | * Returns true on success, false otherwise. |
1420 | */ | 1364 | */ |
1421 | static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, | 1365 | static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, |
1422 | struct tomoyo_single_path_acl_record * | 1366 | struct tomoyo_path_acl *ptr) |
1423 | ptr) | ||
1424 | { | 1367 | { |
1425 | int pos; | 1368 | int pos; |
1426 | u8 bit; | 1369 | u8 bit; |
1427 | const char *atmark = ""; | 1370 | const char *atmark = ""; |
1428 | const char *filename; | 1371 | const char *filename; |
1429 | const u16 perm = ptr->perm; | 1372 | const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); |
1430 | 1373 | ||
1431 | filename = ptr->filename->name; | 1374 | filename = ptr->filename->name; |
1432 | for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION; | 1375 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
1433 | bit++) { | ||
1434 | const char *msg; | 1376 | const char *msg; |
1435 | if (!(perm & (1 << bit))) | 1377 | if (!(perm & (1 << bit))) |
1436 | continue; | 1378 | continue; |
1437 | /* Print "read/write" instead of "read" and "write". */ | 1379 | /* Print "read/write" instead of "read" and "write". */ |
1438 | if ((bit == TOMOYO_TYPE_READ_ACL || | 1380 | if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) |
1439 | bit == TOMOYO_TYPE_WRITE_ACL) | 1381 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
1440 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | ||
1441 | continue; | 1382 | continue; |
1442 | msg = tomoyo_sp2keyword(bit); | 1383 | msg = tomoyo_path2keyword(bit); |
1443 | pos = head->read_avail; | 1384 | pos = head->read_avail; |
1444 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, | 1385 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, |
1445 | atmark, filename)) | 1386 | atmark, filename)) |
@@ -1454,16 +1395,15 @@ static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, | |||
1454 | } | 1395 | } |
1455 | 1396 | ||
1456 | /** | 1397 | /** |
1457 | * tomoyo_print_double_path_acl - Print a double path ACL entry. | 1398 | * tomoyo_print_path2_acl - Print a double path ACL entry. |
1458 | * | 1399 | * |
1459 | * @head: Pointer to "struct tomoyo_io_buffer". | 1400 | * @head: Pointer to "struct tomoyo_io_buffer". |
1460 | * @ptr: Pointer to "struct tomoyo_double_path_acl_record". | 1401 | * @ptr: Pointer to "struct tomoyo_path2_acl". |
1461 | * | 1402 | * |
1462 | * Returns true on success, false otherwise. | 1403 | * Returns true on success, false otherwise. |
1463 | */ | 1404 | */ |
1464 | static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | 1405 | static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, |
1465 | struct tomoyo_double_path_acl_record * | 1406 | struct tomoyo_path2_acl *ptr) |
1466 | ptr) | ||
1467 | { | 1407 | { |
1468 | int pos; | 1408 | int pos; |
1469 | const char *atmark1 = ""; | 1409 | const char *atmark1 = ""; |
@@ -1475,12 +1415,11 @@ static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | |||
1475 | 1415 | ||
1476 | filename1 = ptr->filename1->name; | 1416 | filename1 = ptr->filename1->name; |
1477 | filename2 = ptr->filename2->name; | 1417 | filename2 = ptr->filename2->name; |
1478 | for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION; | 1418 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
1479 | bit++) { | ||
1480 | const char *msg; | 1419 | const char *msg; |
1481 | if (!(perm & (1 << bit))) | 1420 | if (!(perm & (1 << bit))) |
1482 | continue; | 1421 | continue; |
1483 | msg = tomoyo_dp2keyword(bit); | 1422 | msg = tomoyo_path22keyword(bit); |
1484 | pos = head->read_avail; | 1423 | pos = head->read_avail; |
1485 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, | 1424 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, |
1486 | atmark1, filename1, atmark2, filename2)) | 1425 | atmark1, filename1, atmark2, filename2)) |
@@ -1505,23 +1444,17 @@ static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, | |||
1505 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | 1444 | static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, |
1506 | struct tomoyo_acl_info *ptr) | 1445 | struct tomoyo_acl_info *ptr) |
1507 | { | 1446 | { |
1508 | const u8 acl_type = tomoyo_acl_type2(ptr); | 1447 | const u8 acl_type = ptr->type; |
1509 | 1448 | ||
1510 | if (acl_type & TOMOYO_ACL_DELETED) | 1449 | if (acl_type == TOMOYO_TYPE_PATH_ACL) { |
1511 | return true; | 1450 | struct tomoyo_path_acl *acl |
1512 | if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) { | 1451 | = container_of(ptr, struct tomoyo_path_acl, head); |
1513 | struct tomoyo_single_path_acl_record *acl | 1452 | return tomoyo_print_path_acl(head, acl); |
1514 | = container_of(ptr, | ||
1515 | struct tomoyo_single_path_acl_record, | ||
1516 | head); | ||
1517 | return tomoyo_print_single_path_acl(head, acl); | ||
1518 | } | 1453 | } |
1519 | if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) { | 1454 | if (acl_type == TOMOYO_TYPE_PATH2_ACL) { |
1520 | struct tomoyo_double_path_acl_record *acl | 1455 | struct tomoyo_path2_acl *acl |
1521 | = container_of(ptr, | 1456 | = container_of(ptr, struct tomoyo_path2_acl, head); |
1522 | struct tomoyo_double_path_acl_record, | 1457 | return tomoyo_print_path2_acl(head, acl); |
1523 | head); | ||
1524 | return tomoyo_print_double_path_acl(head, acl); | ||
1525 | } | 1458 | } |
1526 | BUG(); /* This must not happen. */ | 1459 | BUG(); /* This must not happen. */ |
1527 | return false; | 1460 | return false; |
@@ -1533,6 +1466,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1533 | * @head: Pointer to "struct tomoyo_io_buffer". | 1466 | * @head: Pointer to "struct tomoyo_io_buffer". |
1534 | * | 1467 | * |
1535 | * Returns 0. | 1468 | * Returns 0. |
1469 | * | ||
1470 | * Caller holds tomoyo_read_lock(). | ||
1536 | */ | 1471 | */ |
1537 | static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | 1472 | static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) |
1538 | { | 1473 | { |
@@ -1544,7 +1479,6 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | |||
1544 | return 0; | 1479 | return 0; |
1545 | if (head->read_step == 0) | 1480 | if (head->read_step == 0) |
1546 | head->read_step = 1; | 1481 | head->read_step = 1; |
1547 | down_read(&tomoyo_domain_list_lock); | ||
1548 | list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { | 1482 | list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { |
1549 | struct tomoyo_domain_info *domain; | 1483 | struct tomoyo_domain_info *domain; |
1550 | const char *quota_exceeded = ""; | 1484 | const char *quota_exceeded = ""; |
@@ -1558,10 +1492,9 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | |||
1558 | /* Print domainname and flags. */ | 1492 | /* Print domainname and flags. */ |
1559 | if (domain->quota_warned) | 1493 | if (domain->quota_warned) |
1560 | quota_exceeded = "quota_exceeded\n"; | 1494 | quota_exceeded = "quota_exceeded\n"; |
1561 | if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED) | 1495 | if (domain->transition_failed) |
1562 | transition_failed = "transition_failed\n"; | 1496 | transition_failed = "transition_failed\n"; |
1563 | if (domain->flags & | 1497 | if (domain->ignore_global_allow_read) |
1564 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) | ||
1565 | ignore_global_allow_read | 1498 | ignore_global_allow_read |
1566 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; | 1499 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
1567 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE | 1500 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE |
@@ -1577,7 +1510,6 @@ acl_loop: | |||
1577 | if (head->read_step == 3) | 1510 | if (head->read_step == 3) |
1578 | goto tail_mark; | 1511 | goto tail_mark; |
1579 | /* Print ACL entries in the domain. */ | 1512 | /* Print ACL entries in the domain. */ |
1580 | down_read(&tomoyo_domain_acl_info_list_lock); | ||
1581 | list_for_each_cookie(apos, head->read_var2, | 1513 | list_for_each_cookie(apos, head->read_var2, |
1582 | &domain->acl_info_list) { | 1514 | &domain->acl_info_list) { |
1583 | struct tomoyo_acl_info *ptr | 1515 | struct tomoyo_acl_info *ptr |
@@ -1587,7 +1519,6 @@ acl_loop: | |||
1587 | if (!done) | 1519 | if (!done) |
1588 | break; | 1520 | break; |
1589 | } | 1521 | } |
1590 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
1591 | if (!done) | 1522 | if (!done) |
1592 | break; | 1523 | break; |
1593 | head->read_step = 3; | 1524 | head->read_step = 3; |
@@ -1599,7 +1530,6 @@ tail_mark: | |||
1599 | if (head->read_single_domain) | 1530 | if (head->read_single_domain) |
1600 | break; | 1531 | break; |
1601 | } | 1532 | } |
1602 | up_read(&tomoyo_domain_list_lock); | ||
1603 | head->read_eof = done; | 1533 | head->read_eof = done; |
1604 | return 0; | 1534 | return 0; |
1605 | } | 1535 | } |
@@ -1615,6 +1545,8 @@ tail_mark: | |||
1615 | * | 1545 | * |
1616 | * ( echo "select " $domainname; echo "use_profile " $profile ) | | 1546 | * ( echo "select " $domainname; echo "use_profile " $profile ) | |
1617 | * /usr/lib/ccs/loadpolicy -d | 1547 | * /usr/lib/ccs/loadpolicy -d |
1548 | * | ||
1549 | * Caller holds tomoyo_read_lock(). | ||
1618 | */ | 1550 | */ |
1619 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | 1551 | static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) |
1620 | { | 1552 | { |
@@ -1626,9 +1558,7 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | |||
1626 | if (!cp) | 1558 | if (!cp) |
1627 | return -EINVAL; | 1559 | return -EINVAL; |
1628 | *cp = '\0'; | 1560 | *cp = '\0'; |
1629 | down_read(&tomoyo_domain_list_lock); | ||
1630 | domain = tomoyo_find_domain(cp + 1); | 1561 | domain = tomoyo_find_domain(cp + 1); |
1631 | up_read(&tomoyo_domain_list_lock); | ||
1632 | if (strict_strtoul(data, 10, &profile)) | 1562 | if (strict_strtoul(data, 10, &profile)) |
1633 | return -EINVAL; | 1563 | return -EINVAL; |
1634 | if (domain && profile < TOMOYO_MAX_PROFILES | 1564 | if (domain && profile < TOMOYO_MAX_PROFILES |
@@ -1650,6 +1580,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) | |||
1650 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) | 1580 | * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) |
1651 | * domainname = $0; } else if ( $1 == "use_profile" ) { | 1581 | * domainname = $0; } else if ( $1 == "use_profile" ) { |
1652 | * print $2 " " domainname; domainname = ""; } } ; ' | 1582 | * print $2 " " domainname; domainname = ""; } } ; ' |
1583 | * | ||
1584 | * Caller holds tomoyo_read_lock(). | ||
1653 | */ | 1585 | */ |
1654 | static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | 1586 | static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) |
1655 | { | 1587 | { |
@@ -1658,7 +1590,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1658 | 1590 | ||
1659 | if (head->read_eof) | 1591 | if (head->read_eof) |
1660 | return 0; | 1592 | return 0; |
1661 | down_read(&tomoyo_domain_list_lock); | ||
1662 | list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { | 1593 | list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { |
1663 | struct tomoyo_domain_info *domain; | 1594 | struct tomoyo_domain_info *domain; |
1664 | domain = list_entry(pos, struct tomoyo_domain_info, list); | 1595 | domain = list_entry(pos, struct tomoyo_domain_info, list); |
@@ -1669,7 +1600,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1669 | if (!done) | 1600 | if (!done) |
1670 | break; | 1601 | break; |
1671 | } | 1602 | } |
1672 | up_read(&tomoyo_domain_list_lock); | ||
1673 | head->read_eof = done; | 1603 | head->read_eof = done; |
1674 | return 0; | 1604 | return 0; |
1675 | } | 1605 | } |
@@ -1707,11 +1637,13 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1707 | const int pid = head->read_step; | 1637 | const int pid = head->read_step; |
1708 | struct task_struct *p; | 1638 | struct task_struct *p; |
1709 | struct tomoyo_domain_info *domain = NULL; | 1639 | struct tomoyo_domain_info *domain = NULL; |
1640 | rcu_read_lock(); | ||
1710 | read_lock(&tasklist_lock); | 1641 | read_lock(&tasklist_lock); |
1711 | p = find_task_by_vpid(pid); | 1642 | p = find_task_by_vpid(pid); |
1712 | if (p) | 1643 | if (p) |
1713 | domain = tomoyo_real_domain(p); | 1644 | domain = tomoyo_real_domain(p); |
1714 | read_unlock(&tasklist_lock); | 1645 | read_unlock(&tasklist_lock); |
1646 | rcu_read_unlock(); | ||
1715 | if (domain) | 1647 | if (domain) |
1716 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, | 1648 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, |
1717 | domain->domainname->name); | 1649 | domain->domainname->name); |
@@ -1726,6 +1658,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1726 | * @head: Pointer to "struct tomoyo_io_buffer". | 1658 | * @head: Pointer to "struct tomoyo_io_buffer". |
1727 | * | 1659 | * |
1728 | * Returns 0 on success, negative value otherwise. | 1660 | * Returns 0 on success, negative value otherwise. |
1661 | * | ||
1662 | * Caller holds tomoyo_read_lock(). | ||
1729 | */ | 1663 | */ |
1730 | static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | 1664 | static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) |
1731 | { | 1665 | { |
@@ -1760,6 +1694,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
1760 | * @head: Pointer to "struct tomoyo_io_buffer". | 1694 | * @head: Pointer to "struct tomoyo_io_buffer". |
1761 | * | 1695 | * |
1762 | * Returns 0 on success, -EINVAL otherwise. | 1696 | * Returns 0 on success, -EINVAL otherwise. |
1697 | * | ||
1698 | * Caller holds tomoyo_read_lock(). | ||
1763 | */ | 1699 | */ |
1764 | static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | 1700 | static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) |
1765 | { | 1701 | { |
@@ -1889,15 +1825,13 @@ void tomoyo_load_policy(const char *filename) | |||
1889 | tomoyo_policy_loaded = true; | 1825 | tomoyo_policy_loaded = true; |
1890 | { /* Check all profiles currently assigned to domains are defined. */ | 1826 | { /* Check all profiles currently assigned to domains are defined. */ |
1891 | struct tomoyo_domain_info *domain; | 1827 | struct tomoyo_domain_info *domain; |
1892 | down_read(&tomoyo_domain_list_lock); | 1828 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
1893 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
1894 | const u8 profile = domain->profile; | 1829 | const u8 profile = domain->profile; |
1895 | if (tomoyo_profile_ptr[profile]) | 1830 | if (tomoyo_profile_ptr[profile]) |
1896 | continue; | 1831 | continue; |
1897 | panic("Profile %u (used by '%s') not defined.\n", | 1832 | panic("Profile %u (used by '%s') not defined.\n", |
1898 | profile, domain->domainname->name); | 1833 | profile, domain->domainname->name); |
1899 | } | 1834 | } |
1900 | up_read(&tomoyo_domain_list_lock); | ||
1901 | } | 1835 | } |
1902 | } | 1836 | } |
1903 | 1837 | ||
@@ -1945,10 +1879,12 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
1945 | * @file: Pointer to "struct file". | 1879 | * @file: Pointer to "struct file". |
1946 | * | 1880 | * |
1947 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. | 1881 | * Associates policy handler and returns 0 on success, -ENOMEM otherwise. |
1882 | * | ||
1883 | * Caller acquires tomoyo_read_lock(). | ||
1948 | */ | 1884 | */ |
1949 | static int tomoyo_open_control(const u8 type, struct file *file) | 1885 | static int tomoyo_open_control(const u8 type, struct file *file) |
1950 | { | 1886 | { |
1951 | struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head)); | 1887 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); |
1952 | 1888 | ||
1953 | if (!head) | 1889 | if (!head) |
1954 | return -ENOMEM; | 1890 | return -ENOMEM; |
@@ -2009,9 +1945,9 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2009 | } else { | 1945 | } else { |
2010 | if (!head->readbuf_size) | 1946 | if (!head->readbuf_size) |
2011 | head->readbuf_size = 4096 * 2; | 1947 | head->readbuf_size = 4096 * 2; |
2012 | head->read_buf = tomoyo_alloc(head->readbuf_size); | 1948 | head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); |
2013 | if (!head->read_buf) { | 1949 | if (!head->read_buf) { |
2014 | tomoyo_free(head); | 1950 | kfree(head); |
2015 | return -ENOMEM; | 1951 | return -ENOMEM; |
2016 | } | 1952 | } |
2017 | } | 1953 | } |
@@ -2023,13 +1959,14 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2023 | head->write = NULL; | 1959 | head->write = NULL; |
2024 | } else if (head->write) { | 1960 | } else if (head->write) { |
2025 | head->writebuf_size = 4096 * 2; | 1961 | head->writebuf_size = 4096 * 2; |
2026 | head->write_buf = tomoyo_alloc(head->writebuf_size); | 1962 | head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); |
2027 | if (!head->write_buf) { | 1963 | if (!head->write_buf) { |
2028 | tomoyo_free(head->read_buf); | 1964 | kfree(head->read_buf); |
2029 | tomoyo_free(head); | 1965 | kfree(head); |
2030 | return -ENOMEM; | 1966 | return -ENOMEM; |
2031 | } | 1967 | } |
2032 | } | 1968 | } |
1969 | head->reader_idx = tomoyo_read_lock(); | ||
2033 | file->private_data = head; | 1970 | file->private_data = head; |
2034 | /* | 1971 | /* |
2035 | * Call the handler now if the file is | 1972 | * Call the handler now if the file is |
@@ -2051,6 +1988,8 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
2051 | * @buffer_len: Size of @buffer. | 1988 | * @buffer_len: Size of @buffer. |
2052 | * | 1989 | * |
2053 | * Returns bytes read on success, negative value otherwise. | 1990 | * Returns bytes read on success, negative value otherwise. |
1991 | * | ||
1992 | * Caller holds tomoyo_read_lock(). | ||
2054 | */ | 1993 | */ |
2055 | static int tomoyo_read_control(struct file *file, char __user *buffer, | 1994 | static int tomoyo_read_control(struct file *file, char __user *buffer, |
2056 | const int buffer_len) | 1995 | const int buffer_len) |
@@ -2094,6 +2033,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, | |||
2094 | * @buffer_len: Size of @buffer. | 2033 | * @buffer_len: Size of @buffer. |
2095 | * | 2034 | * |
2096 | * Returns @buffer_len on success, negative value otherwise. | 2035 | * Returns @buffer_len on success, negative value otherwise. |
2036 | * | ||
2037 | * Caller holds tomoyo_read_lock(). | ||
2097 | */ | 2038 | */ |
2098 | static int tomoyo_write_control(struct file *file, const char __user *buffer, | 2039 | static int tomoyo_write_control(struct file *file, const char __user *buffer, |
2099 | const int buffer_len) | 2040 | const int buffer_len) |
@@ -2144,52 +2085,29 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
2144 | * @file: Pointer to "struct file". | 2085 | * @file: Pointer to "struct file". |
2145 | * | 2086 | * |
2146 | * Releases memory and returns 0. | 2087 | * Releases memory and returns 0. |
2088 | * | ||
2089 | * Caller looses tomoyo_read_lock(). | ||
2147 | */ | 2090 | */ |
2148 | static int tomoyo_close_control(struct file *file) | 2091 | static int tomoyo_close_control(struct file *file) |
2149 | { | 2092 | { |
2150 | struct tomoyo_io_buffer *head = file->private_data; | 2093 | struct tomoyo_io_buffer *head = file->private_data; |
2094 | const bool is_write = !!head->write_buf; | ||
2151 | 2095 | ||
2096 | tomoyo_read_unlock(head->reader_idx); | ||
2152 | /* Release memory used for policy I/O. */ | 2097 | /* Release memory used for policy I/O. */ |
2153 | tomoyo_free(head->read_buf); | 2098 | kfree(head->read_buf); |
2154 | head->read_buf = NULL; | 2099 | head->read_buf = NULL; |
2155 | tomoyo_free(head->write_buf); | 2100 | kfree(head->write_buf); |
2156 | head->write_buf = NULL; | 2101 | head->write_buf = NULL; |
2157 | tomoyo_free(head); | 2102 | kfree(head); |
2158 | head = NULL; | 2103 | head = NULL; |
2159 | file->private_data = NULL; | 2104 | file->private_data = NULL; |
2105 | if (is_write) | ||
2106 | tomoyo_run_gc(); | ||
2160 | return 0; | 2107 | return 0; |
2161 | } | 2108 | } |
2162 | 2109 | ||
2163 | /** | 2110 | /** |
2164 | * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry. | ||
2165 | * | ||
2166 | * @acl_type: Type of ACL entry. | ||
2167 | * | ||
2168 | * Returns pointer to the ACL entry on success, NULL otherwise. | ||
2169 | */ | ||
2170 | void *tomoyo_alloc_acl_element(const u8 acl_type) | ||
2171 | { | ||
2172 | int len; | ||
2173 | struct tomoyo_acl_info *ptr; | ||
2174 | |||
2175 | switch (acl_type) { | ||
2176 | case TOMOYO_TYPE_SINGLE_PATH_ACL: | ||
2177 | len = sizeof(struct tomoyo_single_path_acl_record); | ||
2178 | break; | ||
2179 | case TOMOYO_TYPE_DOUBLE_PATH_ACL: | ||
2180 | len = sizeof(struct tomoyo_double_path_acl_record); | ||
2181 | break; | ||
2182 | default: | ||
2183 | return NULL; | ||
2184 | } | ||
2185 | ptr = tomoyo_alloc_element(len); | ||
2186 | if (!ptr) | ||
2187 | return NULL; | ||
2188 | ptr->type = acl_type; | ||
2189 | return ptr; | ||
2190 | } | ||
2191 | |||
2192 | /** | ||
2193 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. | 2111 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. |
2194 | * | 2112 | * |
2195 | * @inode: Pointer to "struct inode". | 2113 | * @inode: Pointer to "struct inode". |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 92169d29b2db..67bd22dd3e68 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -1,12 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/common.h | 2 | * security/tomoyo/common.h |
3 | * | 3 | * |
4 | * Common functions for TOMOYO. | 4 | * Header file for TOMOYO. |
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | 5 | * |
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
10 | */ | 7 | */ |
11 | 8 | ||
12 | #ifndef _SECURITY_TOMOYO_COMMON_H | 9 | #ifndef _SECURITY_TOMOYO_COMMON_H |
@@ -22,9 +19,119 @@ | |||
22 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
23 | #include <linux/mount.h> | 20 | #include <linux/mount.h> |
24 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/cred.h> | ||
23 | struct linux_binprm; | ||
24 | |||
25 | /********** Constants definitions. **********/ | ||
26 | |||
27 | /* | ||
28 | * TOMOYO uses this hash only when appending a string into the string | ||
29 | * table. Frequency of appending strings is very low. So we don't need | ||
30 | * large (e.g. 64k) hash size. 256 will be sufficient. | ||
31 | */ | ||
32 | #define TOMOYO_HASH_BITS 8 | ||
33 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | ||
34 | |||
35 | /* | ||
36 | * This is the max length of a token. | ||
37 | * | ||
38 | * A token consists of only ASCII printable characters. | ||
39 | * Non printable characters in a token is represented in \ooo style | ||
40 | * octal string. Thus, \ itself is represented as \\. | ||
41 | */ | ||
42 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | ||
43 | |||
44 | /* Profile number is an integer between 0 and 255. */ | ||
45 | #define TOMOYO_MAX_PROFILES 256 | ||
46 | |||
47 | /* Keywords for ACLs. */ | ||
48 | #define TOMOYO_KEYWORD_ALIAS "alias " | ||
49 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | ||
50 | #define TOMOYO_KEYWORD_DELETE "delete " | ||
51 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | ||
52 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " | ||
53 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " | ||
54 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | ||
55 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | ||
56 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | ||
57 | #define TOMOYO_KEYWORD_SELECT "select " | ||
58 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | ||
59 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | ||
60 | /* A domain definition starts with <kernel>. */ | ||
61 | #define TOMOYO_ROOT_NAME "<kernel>" | ||
62 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | ||
63 | |||
64 | /* Index numbers for Access Controls. */ | ||
65 | enum tomoyo_mac_index { | ||
66 | TOMOYO_MAC_FOR_FILE, /* domain_policy.conf */ | ||
67 | TOMOYO_MAX_ACCEPT_ENTRY, | ||
68 | TOMOYO_VERBOSE, | ||
69 | TOMOYO_MAX_CONTROL_INDEX | ||
70 | }; | ||
71 | |||
72 | /* Index numbers for Access Controls. */ | ||
73 | enum tomoyo_acl_entry_type_index { | ||
74 | TOMOYO_TYPE_PATH_ACL, | ||
75 | TOMOYO_TYPE_PATH2_ACL, | ||
76 | }; | ||
77 | |||
78 | /* Index numbers for File Controls. */ | ||
79 | |||
80 | /* | ||
81 | * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set | ||
82 | * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and | ||
83 | * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set. | ||
84 | * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or | ||
85 | * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are | ||
86 | * automatically cleared if TYPE_READ_WRITE_ACL is cleared. | ||
87 | */ | ||
88 | |||
89 | enum tomoyo_path_acl_index { | ||
90 | TOMOYO_TYPE_READ_WRITE, | ||
91 | TOMOYO_TYPE_EXECUTE, | ||
92 | TOMOYO_TYPE_READ, | ||
93 | TOMOYO_TYPE_WRITE, | ||
94 | TOMOYO_TYPE_CREATE, | ||
95 | TOMOYO_TYPE_UNLINK, | ||
96 | TOMOYO_TYPE_MKDIR, | ||
97 | TOMOYO_TYPE_RMDIR, | ||
98 | TOMOYO_TYPE_MKFIFO, | ||
99 | TOMOYO_TYPE_MKSOCK, | ||
100 | TOMOYO_TYPE_MKBLOCK, | ||
101 | TOMOYO_TYPE_MKCHAR, | ||
102 | TOMOYO_TYPE_TRUNCATE, | ||
103 | TOMOYO_TYPE_SYMLINK, | ||
104 | TOMOYO_TYPE_REWRITE, | ||
105 | TOMOYO_TYPE_IOCTL, | ||
106 | TOMOYO_TYPE_CHMOD, | ||
107 | TOMOYO_TYPE_CHOWN, | ||
108 | TOMOYO_TYPE_CHGRP, | ||
109 | TOMOYO_TYPE_CHROOT, | ||
110 | TOMOYO_TYPE_MOUNT, | ||
111 | TOMOYO_TYPE_UMOUNT, | ||
112 | TOMOYO_MAX_PATH_OPERATION | ||
113 | }; | ||
25 | 114 | ||
26 | struct dentry; | 115 | enum tomoyo_path2_acl_index { |
27 | struct vfsmount; | 116 | TOMOYO_TYPE_LINK, |
117 | TOMOYO_TYPE_RENAME, | ||
118 | TOMOYO_TYPE_PIVOT_ROOT, | ||
119 | TOMOYO_MAX_PATH2_OPERATION | ||
120 | }; | ||
121 | |||
122 | enum tomoyo_securityfs_interface_index { | ||
123 | TOMOYO_DOMAINPOLICY, | ||
124 | TOMOYO_EXCEPTIONPOLICY, | ||
125 | TOMOYO_DOMAIN_STATUS, | ||
126 | TOMOYO_PROCESS_STATUS, | ||
127 | TOMOYO_MEMINFO, | ||
128 | TOMOYO_SELFDOMAIN, | ||
129 | TOMOYO_VERSION, | ||
130 | TOMOYO_PROFILE, | ||
131 | TOMOYO_MANAGER | ||
132 | }; | ||
133 | |||
134 | /********** Structure definitions. **********/ | ||
28 | 135 | ||
29 | /* | 136 | /* |
30 | * tomoyo_page_buffer is a structure which is used for holding a pathname | 137 | * tomoyo_page_buffer is a structure which is used for holding a pathname |
@@ -66,13 +173,14 @@ struct tomoyo_path_info { | |||
66 | }; | 173 | }; |
67 | 174 | ||
68 | /* | 175 | /* |
69 | * This is the max length of a token. | 176 | * tomoyo_name_entry is a structure which is used for linking |
70 | * | 177 | * "struct tomoyo_path_info" into tomoyo_name_list . |
71 | * A token consists of only ASCII printable characters. | ||
72 | * Non printable characters in a token is represented in \ooo style | ||
73 | * octal string. Thus, \ itself is represented as \\. | ||
74 | */ | 178 | */ |
75 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | 179 | struct tomoyo_name_entry { |
180 | struct list_head list; | ||
181 | atomic_t users; | ||
182 | struct tomoyo_path_info entry; | ||
183 | }; | ||
76 | 184 | ||
77 | /* | 185 | /* |
78 | * tomoyo_path_info_with_data is a structure which is used for holding a | 186 | * tomoyo_path_info_with_data is a structure which is used for holding a |
@@ -89,7 +197,7 @@ struct tomoyo_path_info { | |||
89 | * "struct tomoyo_path_info_with_data". | 197 | * "struct tomoyo_path_info_with_data". |
90 | */ | 198 | */ |
91 | struct tomoyo_path_info_with_data { | 199 | struct tomoyo_path_info_with_data { |
92 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 200 | /* Keep "head" first, for this pointer is passed to kfree(). */ |
93 | struct tomoyo_path_info head; | 201 | struct tomoyo_path_info head; |
94 | char barrier1[16]; /* Safeguard for overrun. */ | 202 | char barrier1[16]; /* Safeguard for overrun. */ |
95 | char body[TOMOYO_MAX_PATHNAME_LEN]; | 203 | char body[TOMOYO_MAX_PATHNAME_LEN]; |
@@ -101,30 +209,19 @@ struct tomoyo_path_info_with_data { | |||
101 | * | 209 | * |
102 | * (1) "list" which is linked to the ->acl_info_list of | 210 | * (1) "list" which is linked to the ->acl_info_list of |
103 | * "struct tomoyo_domain_info" | 211 | * "struct tomoyo_domain_info" |
104 | * (2) "type" which tells | 212 | * (2) "type" which tells type of the entry (either |
105 | * (a) type & 0x7F : type of the entry (either | 213 | * "struct tomoyo_path_acl" or "struct tomoyo_path2_acl"). |
106 | * "struct tomoyo_single_path_acl_record" or | ||
107 | * "struct tomoyo_double_path_acl_record") | ||
108 | * (b) type & 0x80 : whether the entry is marked as "deleted". | ||
109 | * | 214 | * |
110 | * Packing "struct tomoyo_acl_info" allows | 215 | * Packing "struct tomoyo_acl_info" allows |
111 | * "struct tomoyo_single_path_acl_record" to embed "u16" and | 216 | * "struct tomoyo_path_acl" to embed "u8" + "u16" and |
112 | * "struct tomoyo_double_path_acl_record" to embed "u8" | 217 | * "struct tomoyo_path2_acl" to embed "u8" |
113 | * without enlarging their structure size. | 218 | * without enlarging their structure size. |
114 | */ | 219 | */ |
115 | struct tomoyo_acl_info { | 220 | struct tomoyo_acl_info { |
116 | struct list_head list; | 221 | struct list_head list; |
117 | /* | ||
118 | * Type of this ACL entry. | ||
119 | * | ||
120 | * MSB is is_deleted flag. | ||
121 | */ | ||
122 | u8 type; | 222 | u8 type; |
123 | } __packed; | 223 | } __packed; |
124 | 224 | ||
125 | /* This ACL entry is deleted. */ | ||
126 | #define TOMOYO_ACL_DELETED 0x80 | ||
127 | |||
128 | /* | 225 | /* |
129 | * tomoyo_domain_info is a structure which is used for holding permissions | 226 | * tomoyo_domain_info is a structure which is used for holding permissions |
130 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | 227 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. |
@@ -138,7 +235,17 @@ struct tomoyo_acl_info { | |||
138 | * "deleted", false otherwise. | 235 | * "deleted", false otherwise. |
139 | * (6) "quota_warned" is a bool which is used for suppressing warning message | 236 | * (6) "quota_warned" is a bool which is used for suppressing warning message |
140 | * when learning mode learned too much entries. | 237 | * when learning mode learned too much entries. |
141 | * (7) "flags" which remembers this domain's attributes. | 238 | * (7) "ignore_global_allow_read" is a bool which is true if this domain |
239 | * should ignore "allow_read" directive in exception policy. | ||
240 | * (8) "transition_failed" is a bool which is set to true when this domain was | ||
241 | * unable to create a new domain at tomoyo_find_next_domain() because the | ||
242 | * name of the domain to be created was too long or it could not allocate | ||
243 | * memory. If set to true, more than one process continued execve() | ||
244 | * without domain transition. | ||
245 | * (9) "users" is an atomic_t that holds how many "struct cred"->security | ||
246 | * are referring this "struct tomoyo_domain_info". If is_deleted == true | ||
247 | * and users == 0, this struct will be kfree()d upon next garbage | ||
248 | * collection. | ||
142 | * | 249 | * |
143 | * A domain's lifecycle is an analogy of files on / directory. | 250 | * A domain's lifecycle is an analogy of files on / directory. |
144 | * Multiple domains with the same domainname cannot be created (as with | 251 | * Multiple domains with the same domainname cannot be created (as with |
@@ -155,25 +262,13 @@ struct tomoyo_domain_info { | |||
155 | u8 profile; /* Profile number to use. */ | 262 | u8 profile; /* Profile number to use. */ |
156 | bool is_deleted; /* Delete flag. */ | 263 | bool is_deleted; /* Delete flag. */ |
157 | bool quota_warned; /* Quota warnning flag. */ | 264 | bool quota_warned; /* Quota warnning flag. */ |
158 | /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */ | 265 | bool ignore_global_allow_read; /* Ignore "allow_read" flag. */ |
159 | u8 flags; | 266 | bool transition_failed; /* Domain transition failed flag. */ |
267 | atomic_t users; /* Number of referring credentials. */ | ||
160 | }; | 268 | }; |
161 | 269 | ||
162 | /* Profile number is an integer between 0 and 255. */ | ||
163 | #define TOMOYO_MAX_PROFILES 256 | ||
164 | |||
165 | /* Ignore "allow_read" directive in exception policy. */ | ||
166 | #define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1 | ||
167 | /* | ||
168 | * This domain was unable to create a new domain at tomoyo_find_next_domain() | ||
169 | * because the name of the domain to be created was too long or | ||
170 | * it could not allocate memory. | ||
171 | * More than one process continued execve() without domain transition. | ||
172 | */ | ||
173 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 | ||
174 | |||
175 | /* | 270 | /* |
176 | * tomoyo_single_path_acl_record is a structure which is used for holding an | 271 | * tomoyo_path_acl is a structure which is used for holding an |
177 | * entry with one pathname operation (e.g. open(), mkdir()). | 272 | * entry with one pathname operation (e.g. open(), mkdir()). |
178 | * It has following fields. | 273 | * It has following fields. |
179 | * | 274 | * |
@@ -184,18 +279,21 @@ struct tomoyo_domain_info { | |||
184 | * Directives held by this structure are "allow_read/write", "allow_execute", | 279 | * Directives held by this structure are "allow_read/write", "allow_execute", |
185 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | 280 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", |
186 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", | 281 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", |
187 | * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". | 282 | * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite", |
283 | * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount" | ||
284 | * and "allow_unmount". | ||
188 | */ | 285 | */ |
189 | struct tomoyo_single_path_acl_record { | 286 | struct tomoyo_path_acl { |
190 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ | 287 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ |
288 | u8 perm_high; | ||
191 | u16 perm; | 289 | u16 perm; |
192 | /* Pointer to single pathname. */ | 290 | /* Pointer to single pathname. */ |
193 | const struct tomoyo_path_info *filename; | 291 | const struct tomoyo_path_info *filename; |
194 | }; | 292 | }; |
195 | 293 | ||
196 | /* | 294 | /* |
197 | * tomoyo_double_path_acl_record is a structure which is used for holding an | 295 | * tomoyo_path2_acl is a structure which is used for holding an |
198 | * entry with two pathnames operation (i.e. link() and rename()). | 296 | * entry with two pathnames operation (i.e. link(), rename() and pivot_root()). |
199 | * It has following fields. | 297 | * It has following fields. |
200 | * | 298 | * |
201 | * (1) "head" which is a "struct tomoyo_acl_info". | 299 | * (1) "head" which is a "struct tomoyo_acl_info". |
@@ -203,10 +301,11 @@ struct tomoyo_single_path_acl_record { | |||
203 | * (3) "filename1" is the source/old pathname. | 301 | * (3) "filename1" is the source/old pathname. |
204 | * (4) "filename2" is the destination/new pathname. | 302 | * (4) "filename2" is the destination/new pathname. |
205 | * | 303 | * |
206 | * Directives held by this structure are "allow_rename" and "allow_link". | 304 | * Directives held by this structure are "allow_rename", "allow_link" and |
305 | * "allow_pivot_root". | ||
207 | */ | 306 | */ |
208 | struct tomoyo_double_path_acl_record { | 307 | struct tomoyo_path2_acl { |
209 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ | 308 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ |
210 | u8 perm; | 309 | u8 perm; |
211 | /* Pointer to single pathname. */ | 310 | /* Pointer to single pathname. */ |
212 | const struct tomoyo_path_info *filename1; | 311 | const struct tomoyo_path_info *filename1; |
@@ -214,29 +313,6 @@ struct tomoyo_double_path_acl_record { | |||
214 | const struct tomoyo_path_info *filename2; | 313 | const struct tomoyo_path_info *filename2; |
215 | }; | 314 | }; |
216 | 315 | ||
217 | /* Keywords for ACLs. */ | ||
218 | #define TOMOYO_KEYWORD_ALIAS "alias " | ||
219 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | ||
220 | #define TOMOYO_KEYWORD_DELETE "delete " | ||
221 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | ||
222 | #define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " | ||
223 | #define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " | ||
224 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | ||
225 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | ||
226 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | ||
227 | #define TOMOYO_KEYWORD_SELECT "select " | ||
228 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | ||
229 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | ||
230 | /* A domain definition starts with <kernel>. */ | ||
231 | #define TOMOYO_ROOT_NAME "<kernel>" | ||
232 | #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) | ||
233 | |||
234 | /* Index numbers for Access Controls. */ | ||
235 | #define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ | ||
236 | #define TOMOYO_MAX_ACCEPT_ENTRY 1 | ||
237 | #define TOMOYO_VERBOSE 2 | ||
238 | #define TOMOYO_MAX_CONTROL_INDEX 3 | ||
239 | |||
240 | /* | 316 | /* |
241 | * tomoyo_io_buffer is a structure which is used for reading and modifying | 317 | * tomoyo_io_buffer is a structure which is used for reading and modifying |
242 | * configuration via /sys/kernel/security/tomoyo/ interface. | 318 | * configuration via /sys/kernel/security/tomoyo/ interface. |
@@ -265,6 +341,8 @@ struct tomoyo_io_buffer { | |||
265 | int (*write) (struct tomoyo_io_buffer *); | 341 | int (*write) (struct tomoyo_io_buffer *); |
266 | /* Exclusive lock for this structure. */ | 342 | /* Exclusive lock for this structure. */ |
267 | struct mutex io_sem; | 343 | struct mutex io_sem; |
344 | /* Index returned by tomoyo_read_lock(). */ | ||
345 | int reader_idx; | ||
268 | /* The position currently reading from. */ | 346 | /* The position currently reading from. */ |
269 | struct list_head *read_var1; | 347 | struct list_head *read_var1; |
270 | /* Extra variables for reading. */ | 348 | /* Extra variables for reading. */ |
@@ -293,18 +371,159 @@ struct tomoyo_io_buffer { | |||
293 | int writebuf_size; | 371 | int writebuf_size; |
294 | }; | 372 | }; |
295 | 373 | ||
374 | /* | ||
375 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
376 | * "allow_read" entries. | ||
377 | * It has following fields. | ||
378 | * | ||
379 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
380 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
381 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
382 | * otherwise. | ||
383 | */ | ||
384 | struct tomoyo_globally_readable_file_entry { | ||
385 | struct list_head list; | ||
386 | const struct tomoyo_path_info *filename; | ||
387 | bool is_deleted; | ||
388 | }; | ||
389 | |||
390 | /* | ||
391 | * tomoyo_pattern_entry is a structure which is used for holding | ||
392 | * "tomoyo_pattern_list" entries. | ||
393 | * It has following fields. | ||
394 | * | ||
395 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
396 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
397 | * to pathname patterns during learning mode. | ||
398 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
399 | * otherwise. | ||
400 | */ | ||
401 | struct tomoyo_pattern_entry { | ||
402 | struct list_head list; | ||
403 | const struct tomoyo_path_info *pattern; | ||
404 | bool is_deleted; | ||
405 | }; | ||
406 | |||
407 | /* | ||
408 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
409 | * "deny_rewrite" entries. | ||
410 | * It has following fields. | ||
411 | * | ||
412 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
413 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
414 | * already existing content. | ||
415 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
416 | * otherwise. | ||
417 | */ | ||
418 | struct tomoyo_no_rewrite_entry { | ||
419 | struct list_head list; | ||
420 | const struct tomoyo_path_info *pattern; | ||
421 | bool is_deleted; | ||
422 | }; | ||
423 | |||
424 | /* | ||
425 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
426 | * "initialize_domain" and "no_initialize_domain" entries. | ||
427 | * It has following fields. | ||
428 | * | ||
429 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
430 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
431 | * domainname". This field is NULL if "from" clause is not specified. | ||
432 | * (3) "program" which is a program's pathname. | ||
433 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
434 | * otherwise. | ||
435 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
436 | * otherwise. | ||
437 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
438 | * component of a domainname", false otherwise. | ||
439 | */ | ||
440 | struct tomoyo_domain_initializer_entry { | ||
441 | struct list_head list; | ||
442 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | ||
443 | const struct tomoyo_path_info *program; | ||
444 | bool is_deleted; | ||
445 | bool is_not; /* True if this entry is "no_initialize_domain". */ | ||
446 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
447 | bool is_last_name; | ||
448 | }; | ||
449 | |||
450 | /* | ||
451 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
452 | * "keep_domain" and "no_keep_domain" entries. | ||
453 | * It has following fields. | ||
454 | * | ||
455 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
456 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
457 | * domainname". | ||
458 | * (3) "program" which is a program's pathname. | ||
459 | * This field is NULL if "from" clause is not specified. | ||
460 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
461 | * otherwise. | ||
462 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
463 | * otherwise. | ||
464 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
465 | * component of a domainname", false otherwise. | ||
466 | */ | ||
467 | struct tomoyo_domain_keeper_entry { | ||
468 | struct list_head list; | ||
469 | const struct tomoyo_path_info *domainname; | ||
470 | const struct tomoyo_path_info *program; /* This may be NULL */ | ||
471 | bool is_deleted; | ||
472 | bool is_not; /* True if this entry is "no_keep_domain". */ | ||
473 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
474 | bool is_last_name; | ||
475 | }; | ||
476 | |||
477 | /* | ||
478 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
479 | * It has following fields. | ||
480 | * | ||
481 | * (1) "list" which is linked to tomoyo_alias_list . | ||
482 | * (2) "original_name" which is a dereferenced pathname. | ||
483 | * (3) "aliased_name" which is a symlink's pathname. | ||
484 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
485 | * otherwise. | ||
486 | */ | ||
487 | struct tomoyo_alias_entry { | ||
488 | struct list_head list; | ||
489 | const struct tomoyo_path_info *original_name; | ||
490 | const struct tomoyo_path_info *aliased_name; | ||
491 | bool is_deleted; | ||
492 | }; | ||
493 | |||
494 | /* | ||
495 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
496 | * domainnames or programs which are permitted to modify configuration via | ||
497 | * /sys/kernel/security/tomoyo/ interface. | ||
498 | * It has following fields. | ||
499 | * | ||
500 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
501 | * (2) "manager" is a domainname or a program's pathname. | ||
502 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
503 | * otherwise. | ||
504 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
505 | * otherwise. | ||
506 | */ | ||
507 | struct tomoyo_policy_manager_entry { | ||
508 | struct list_head list; | ||
509 | /* A path to program or a domainname. */ | ||
510 | const struct tomoyo_path_info *manager; | ||
511 | bool is_domain; /* True if manager is a domainname. */ | ||
512 | bool is_deleted; /* True if this entry is deleted. */ | ||
513 | }; | ||
514 | |||
515 | /********** Function prototypes. **********/ | ||
516 | |||
296 | /* Check whether the domain has too many ACL entries to hold. */ | 517 | /* Check whether the domain has too many ACL entries to hold. */ |
297 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); | 518 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); |
298 | /* Transactional sprintf() for policy dump. */ | 519 | /* Transactional sprintf() for policy dump. */ |
299 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) | 520 | bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) |
300 | __attribute__ ((format(printf, 2, 3))); | 521 | __attribute__ ((format(printf, 2, 3))); |
301 | /* Check whether the domainname is correct. */ | 522 | /* Check whether the domainname is correct. */ |
302 | bool tomoyo_is_correct_domain(const unsigned char *domainname, | 523 | bool tomoyo_is_correct_domain(const unsigned char *domainname); |
303 | const char *function); | ||
304 | /* Check whether the token is correct. */ | 524 | /* Check whether the token is correct. */ |
305 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | 525 | bool tomoyo_is_correct_path(const char *filename, const s8 start_type, |
306 | const s8 pattern_type, const s8 end_type, | 526 | const s8 pattern_type, const s8 end_type); |
307 | const char *function); | ||
308 | /* Check whether the token can be a domainname. */ | 527 | /* Check whether the token can be a domainname. */ |
309 | bool tomoyo_is_domain_def(const unsigned char *buffer); | 528 | bool tomoyo_is_domain_def(const unsigned char *buffer); |
310 | /* Check whether the given filename matches the given pattern. */ | 529 | /* Check whether the given filename matches the given pattern. */ |
@@ -328,13 +547,13 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); | |||
328 | /* Write domain policy violation warning message to console? */ | 547 | /* Write domain policy violation warning message to console? */ |
329 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); | 548 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); |
330 | /* Convert double path operation to operation name. */ | 549 | /* Convert double path operation to operation name. */ |
331 | const char *tomoyo_dp2keyword(const u8 operation); | 550 | const char *tomoyo_path22keyword(const u8 operation); |
332 | /* Get the last component of the given domainname. */ | 551 | /* Get the last component of the given domainname. */ |
333 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | 552 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); |
334 | /* Get warning message. */ | 553 | /* Get warning message. */ |
335 | const char *tomoyo_get_msg(const bool is_enforce); | 554 | const char *tomoyo_get_msg(const bool is_enforce); |
336 | /* Convert single path operation to operation name. */ | 555 | /* Convert single path operation to operation name. */ |
337 | const char *tomoyo_sp2keyword(const u8 operation); | 556 | const char *tomoyo_path2keyword(const u8 operation); |
338 | /* Create "alias" entry in exception policy. */ | 557 | /* Create "alias" entry in exception policy. */ |
339 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 558 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
340 | /* | 559 | /* |
@@ -370,33 +589,107 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
370 | /* Check mode for specified functionality. */ | 589 | /* Check mode for specified functionality. */ |
371 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | 590 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, |
372 | const u8 index); | 591 | const u8 index); |
373 | /* Allocate memory for structures. */ | ||
374 | void *tomoyo_alloc_acl_element(const u8 acl_type); | ||
375 | /* Fill in "struct tomoyo_path_info" members. */ | 592 | /* Fill in "struct tomoyo_path_info" members. */ |
376 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | 593 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); |
377 | /* Run policy loader when /sbin/init starts. */ | 594 | /* Run policy loader when /sbin/init starts. */ |
378 | void tomoyo_load_policy(const char *filename); | 595 | void tomoyo_load_policy(const char *filename); |
379 | /* Change "struct tomoyo_domain_info"->flags. */ | ||
380 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | ||
381 | const bool is_delete, const u8 flags); | ||
382 | 596 | ||
383 | /* strcmp() for "struct tomoyo_path_info" structure. */ | 597 | /* Convert binary string to ascii string. */ |
384 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, | 598 | int tomoyo_encode(char *buffer, int buflen, const char *str); |
385 | const struct tomoyo_path_info *b) | 599 | |
600 | /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */ | ||
601 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | ||
602 | int newname_len); | ||
603 | |||
604 | /* | ||
605 | * Returns realpath(3) of the given pathname but ignores chroot'ed root. | ||
606 | * These functions use kzalloc(), so the caller must call kfree() | ||
607 | * if these functions didn't return NULL. | ||
608 | */ | ||
609 | char *tomoyo_realpath(const char *pathname); | ||
610 | /* | ||
611 | * Same with tomoyo_realpath() except that it doesn't follow the final symlink. | ||
612 | */ | ||
613 | char *tomoyo_realpath_nofollow(const char *pathname); | ||
614 | /* Same with tomoyo_realpath() except that the pathname is already solved. */ | ||
615 | char *tomoyo_realpath_from_path(struct path *path); | ||
616 | |||
617 | /* Check memory quota. */ | ||
618 | bool tomoyo_memory_ok(void *ptr); | ||
619 | |||
620 | /* | ||
621 | * Keep the given name on the RAM. | ||
622 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
623 | */ | ||
624 | const struct tomoyo_path_info *tomoyo_get_name(const char *name); | ||
625 | |||
626 | /* Check for memory usage. */ | ||
627 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); | ||
628 | |||
629 | /* Set memory quota. */ | ||
630 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); | ||
631 | |||
632 | /* Initialize realpath related code. */ | ||
633 | void __init tomoyo_realpath_init(void); | ||
634 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | ||
635 | const struct tomoyo_path_info *filename); | ||
636 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | ||
637 | struct path *path, const int flag); | ||
638 | int tomoyo_path_perm(const u8 operation, struct path *path); | ||
639 | int tomoyo_path2_perm(const u8 operation, struct path *path1, | ||
640 | struct path *path2); | ||
641 | int tomoyo_check_rewrite_permission(struct file *filp); | ||
642 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | ||
643 | |||
644 | /* Run garbage collector. */ | ||
645 | void tomoyo_run_gc(void); | ||
646 | |||
647 | void tomoyo_memory_free(void *ptr); | ||
648 | |||
649 | /********** External variable definitions. **********/ | ||
650 | |||
651 | /* Lock for GC. */ | ||
652 | extern struct srcu_struct tomoyo_ss; | ||
653 | |||
654 | /* The list for "struct tomoyo_domain_info". */ | ||
655 | extern struct list_head tomoyo_domain_list; | ||
656 | |||
657 | extern struct list_head tomoyo_domain_initializer_list; | ||
658 | extern struct list_head tomoyo_domain_keeper_list; | ||
659 | extern struct list_head tomoyo_alias_list; | ||
660 | extern struct list_head tomoyo_globally_readable_list; | ||
661 | extern struct list_head tomoyo_pattern_list; | ||
662 | extern struct list_head tomoyo_no_rewrite_list; | ||
663 | extern struct list_head tomoyo_policy_manager_list; | ||
664 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | ||
665 | extern struct mutex tomoyo_name_list_lock; | ||
666 | |||
667 | /* Lock for protecting policy. */ | ||
668 | extern struct mutex tomoyo_policy_lock; | ||
669 | |||
670 | /* Has /sbin/init started? */ | ||
671 | extern bool tomoyo_policy_loaded; | ||
672 | |||
673 | /* The kernel's domain. */ | ||
674 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | ||
675 | |||
676 | /********** Inlined functions. **********/ | ||
677 | |||
678 | static inline int tomoyo_read_lock(void) | ||
386 | { | 679 | { |
387 | return a->hash != b->hash || strcmp(a->name, b->name); | 680 | return srcu_read_lock(&tomoyo_ss); |
388 | } | 681 | } |
389 | 682 | ||
390 | /* Get type of an ACL entry. */ | 683 | static inline void tomoyo_read_unlock(int idx) |
391 | static inline u8 tomoyo_acl_type1(struct tomoyo_acl_info *ptr) | ||
392 | { | 684 | { |
393 | return ptr->type & ~TOMOYO_ACL_DELETED; | 685 | srcu_read_unlock(&tomoyo_ss, idx); |
394 | } | 686 | } |
395 | 687 | ||
396 | /* Get type of an ACL entry. */ | 688 | /* strcmp() for "struct tomoyo_path_info" structure. */ |
397 | static inline u8 tomoyo_acl_type2(struct tomoyo_acl_info *ptr) | 689 | static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, |
690 | const struct tomoyo_path_info *b) | ||
398 | { | 691 | { |
399 | return ptr->type; | 692 | return a->hash != b->hash || strcmp(a->name, b->name); |
400 | } | 693 | } |
401 | 694 | ||
402 | /** | 695 | /** |
@@ -423,18 +716,25 @@ static inline bool tomoyo_is_invalid(const unsigned char c) | |||
423 | return c && (c <= ' ' || c >= 127); | 716 | return c && (c <= ' ' || c >= 127); |
424 | } | 717 | } |
425 | 718 | ||
426 | /* The list for "struct tomoyo_domain_info". */ | 719 | static inline void tomoyo_put_name(const struct tomoyo_path_info *name) |
427 | extern struct list_head tomoyo_domain_list; | 720 | { |
428 | extern struct rw_semaphore tomoyo_domain_list_lock; | 721 | if (name) { |
429 | 722 | struct tomoyo_name_entry *ptr = | |
430 | /* Lock for domain->acl_info_list. */ | 723 | container_of(name, struct tomoyo_name_entry, entry); |
431 | extern struct rw_semaphore tomoyo_domain_acl_info_list_lock; | 724 | atomic_dec(&ptr->users); |
725 | } | ||
726 | } | ||
432 | 727 | ||
433 | /* Has /sbin/init started? */ | 728 | static inline struct tomoyo_domain_info *tomoyo_domain(void) |
434 | extern bool tomoyo_policy_loaded; | 729 | { |
730 | return current_cred()->security; | ||
731 | } | ||
435 | 732 | ||
436 | /* The kernel's domain. */ | 733 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct |
437 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | 734 | *task) |
735 | { | ||
736 | return task_cred_xxx(task, security); | ||
737 | } | ||
438 | 738 | ||
439 | /** | 739 | /** |
440 | * list_for_each_cookie - iterate over a list with cookie. | 740 | * list_for_each_cookie - iterate over a list with cookie. |
@@ -442,16 +742,16 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; | |||
442 | * @cookie: the &struct list_head to use as a cookie. | 742 | * @cookie: the &struct list_head to use as a cookie. |
443 | * @head: the head for your list. | 743 | * @head: the head for your list. |
444 | * | 744 | * |
445 | * Same with list_for_each() except that this primitive uses @cookie | 745 | * Same with list_for_each_rcu() except that this primitive uses @cookie |
446 | * so that we can continue iteration. | 746 | * so that we can continue iteration. |
447 | * @cookie must be NULL when iteration starts, and @cookie will become | 747 | * @cookie must be NULL when iteration starts, and @cookie will become |
448 | * NULL when iteration finishes. | 748 | * NULL when iteration finishes. |
449 | */ | 749 | */ |
450 | #define list_for_each_cookie(pos, cookie, head) \ | 750 | #define list_for_each_cookie(pos, cookie, head) \ |
451 | for (({ if (!cookie) \ | 751 | for (({ if (!cookie) \ |
452 | cookie = head; }), \ | 752 | cookie = head; }), \ |
453 | pos = (cookie)->next; \ | 753 | pos = rcu_dereference((cookie)->next); \ |
454 | prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ | 754 | prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ |
455 | (cookie) = pos, pos = pos->next) | 755 | (cookie) = pos, pos = rcu_dereference(pos->next)) |
456 | 756 | ||
457 | #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ | 757 | #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index fcf52accce2b..66caaa1b842a 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -10,8 +10,6 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | ||
14 | #include "realpath.h" | ||
15 | #include <linux/binfmts.h> | 13 | #include <linux/binfmts.h> |
16 | 14 | ||
17 | /* Variables definitions.*/ | 15 | /* Variables definitions.*/ |
@@ -58,99 +56,6 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
58 | * exceptions. | 56 | * exceptions. |
59 | */ | 57 | */ |
60 | LIST_HEAD(tomoyo_domain_list); | 58 | LIST_HEAD(tomoyo_domain_list); |
61 | DECLARE_RWSEM(tomoyo_domain_list_lock); | ||
62 | |||
63 | /* | ||
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
79 | struct tomoyo_domain_initializer_entry { | ||
80 | struct list_head list; | ||
81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | ||
82 | const struct tomoyo_path_info *program; | ||
83 | bool is_deleted; | ||
84 | bool is_not; /* True if this entry is "no_initialize_domain". */ | ||
85 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
86 | bool is_last_name; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
106 | struct tomoyo_domain_keeper_entry { | ||
107 | struct list_head list; | ||
108 | const struct tomoyo_path_info *domainname; | ||
109 | const struct tomoyo_path_info *program; /* This may be NULL */ | ||
110 | bool is_deleted; | ||
111 | bool is_not; /* True if this entry is "no_keep_domain". */ | ||
112 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
113 | bool is_last_name; | ||
114 | }; | ||
115 | |||
116 | /* | ||
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
126 | struct tomoyo_alias_entry { | ||
127 | struct list_head list; | ||
128 | const struct tomoyo_path_info *original_name; | ||
129 | const struct tomoyo_path_info *aliased_name; | ||
130 | bool is_deleted; | ||
131 | }; | ||
132 | |||
133 | /** | ||
134 | * tomoyo_set_domain_flag - Set or clear domain's attribute flags. | ||
135 | * | ||
136 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
137 | * @is_delete: True if it is a delete request. | ||
138 | * @flags: Flags to set or clear. | ||
139 | * | ||
140 | * Returns nothing. | ||
141 | */ | ||
142 | void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | ||
143 | const bool is_delete, const u8 flags) | ||
144 | { | ||
145 | /* We need to serialize because this is bitfield operation. */ | ||
146 | static DEFINE_SPINLOCK(lock); | ||
147 | spin_lock(&lock); | ||
148 | if (!is_delete) | ||
149 | domain->flags |= flags; | ||
150 | else | ||
151 | domain->flags &= ~flags; | ||
152 | spin_unlock(&lock); | ||
153 | } | ||
154 | 59 | ||
155 | /** | 60 | /** |
156 | * tomoyo_get_last_name - Get last component of a domainname. | 61 | * tomoyo_get_last_name - Get last component of a domainname. |
@@ -205,8 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
205 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | 110 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain |
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | 111 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. |
207 | */ | 112 | */ |
208 | static LIST_HEAD(tomoyo_domain_initializer_list); | 113 | LIST_HEAD(tomoyo_domain_initializer_list); |
209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | ||
210 | 114 | ||
211 | /** | 115 | /** |
212 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 116 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. |
@@ -217,59 +121,65 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | |||
217 | * @is_delete: True if it is a delete request. | 121 | * @is_delete: True if it is a delete request. |
218 | * | 122 | * |
219 | * Returns 0 on success, negative value otherwise. | 123 | * Returns 0 on success, negative value otherwise. |
124 | * | ||
125 | * Caller holds tomoyo_read_lock(). | ||
220 | */ | 126 | */ |
221 | static int tomoyo_update_domain_initializer_entry(const char *domainname, | 127 | static int tomoyo_update_domain_initializer_entry(const char *domainname, |
222 | const char *program, | 128 | const char *program, |
223 | const bool is_not, | 129 | const bool is_not, |
224 | const bool is_delete) | 130 | const bool is_delete) |
225 | { | 131 | { |
226 | struct tomoyo_domain_initializer_entry *new_entry; | 132 | struct tomoyo_domain_initializer_entry *entry = NULL; |
227 | struct tomoyo_domain_initializer_entry *ptr; | 133 | struct tomoyo_domain_initializer_entry *ptr; |
228 | const struct tomoyo_path_info *saved_program; | 134 | const struct tomoyo_path_info *saved_program = NULL; |
229 | const struct tomoyo_path_info *saved_domainname = NULL; | 135 | const struct tomoyo_path_info *saved_domainname = NULL; |
230 | int error = -ENOMEM; | 136 | int error = is_delete ? -ENOENT : -ENOMEM; |
231 | bool is_last_name = false; | 137 | bool is_last_name = false; |
232 | 138 | ||
233 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 139 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
234 | return -EINVAL; /* No patterns allowed. */ | 140 | return -EINVAL; /* No patterns allowed. */ |
235 | if (domainname) { | 141 | if (domainname) { |
236 | if (!tomoyo_is_domain_def(domainname) && | 142 | if (!tomoyo_is_domain_def(domainname) && |
237 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 143 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
238 | is_last_name = true; | 144 | is_last_name = true; |
239 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 145 | else if (!tomoyo_is_correct_domain(domainname)) |
240 | return -EINVAL; | 146 | return -EINVAL; |
241 | saved_domainname = tomoyo_save_name(domainname); | 147 | saved_domainname = tomoyo_get_name(domainname); |
242 | if (!saved_domainname) | 148 | if (!saved_domainname) |
243 | return -ENOMEM; | 149 | goto out; |
244 | } | 150 | } |
245 | saved_program = tomoyo_save_name(program); | 151 | saved_program = tomoyo_get_name(program); |
246 | if (!saved_program) | 152 | if (!saved_program) |
247 | return -ENOMEM; | 153 | goto out; |
248 | down_write(&tomoyo_domain_initializer_list_lock); | 154 | if (!is_delete) |
249 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 155 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
156 | mutex_lock(&tomoyo_policy_lock); | ||
157 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { | ||
250 | if (ptr->is_not != is_not || | 158 | if (ptr->is_not != is_not || |
251 | ptr->domainname != saved_domainname || | 159 | ptr->domainname != saved_domainname || |
252 | ptr->program != saved_program) | 160 | ptr->program != saved_program) |
253 | continue; | 161 | continue; |
254 | ptr->is_deleted = is_delete; | 162 | ptr->is_deleted = is_delete; |
255 | error = 0; | 163 | error = 0; |
256 | goto out; | 164 | break; |
257 | } | 165 | } |
258 | if (is_delete) { | 166 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
259 | error = -ENOENT; | 167 | entry->domainname = saved_domainname; |
260 | goto out; | 168 | saved_domainname = NULL; |
169 | entry->program = saved_program; | ||
170 | saved_program = NULL; | ||
171 | entry->is_not = is_not; | ||
172 | entry->is_last_name = is_last_name; | ||
173 | list_add_tail_rcu(&entry->list, | ||
174 | &tomoyo_domain_initializer_list); | ||
175 | entry = NULL; | ||
176 | error = 0; | ||
261 | } | 177 | } |
262 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 178 | mutex_unlock(&tomoyo_policy_lock); |
263 | if (!new_entry) | ||
264 | goto out; | ||
265 | new_entry->domainname = saved_domainname; | ||
266 | new_entry->program = saved_program; | ||
267 | new_entry->is_not = is_not; | ||
268 | new_entry->is_last_name = is_last_name; | ||
269 | list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); | ||
270 | error = 0; | ||
271 | out: | 179 | out: |
272 | up_write(&tomoyo_domain_initializer_list_lock); | 180 | tomoyo_put_name(saved_domainname); |
181 | tomoyo_put_name(saved_program); | ||
182 | kfree(entry); | ||
273 | return error; | 183 | return error; |
274 | } | 184 | } |
275 | 185 | ||
@@ -279,13 +189,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
279 | * @head: Pointer to "struct tomoyo_io_buffer". | 189 | * @head: Pointer to "struct tomoyo_io_buffer". |
280 | * | 190 | * |
281 | * Returns true on success, false otherwise. | 191 | * Returns true on success, false otherwise. |
192 | * | ||
193 | * Caller holds tomoyo_read_lock(). | ||
282 | */ | 194 | */ |
283 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | 195 | bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) |
284 | { | 196 | { |
285 | struct list_head *pos; | 197 | struct list_head *pos; |
286 | bool done = true; | 198 | bool done = true; |
287 | 199 | ||
288 | down_read(&tomoyo_domain_initializer_list_lock); | ||
289 | list_for_each_cookie(pos, head->read_var2, | 200 | list_for_each_cookie(pos, head->read_var2, |
290 | &tomoyo_domain_initializer_list) { | 201 | &tomoyo_domain_initializer_list) { |
291 | const char *no; | 202 | const char *no; |
@@ -308,7 +219,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
308 | if (!done) | 219 | if (!done) |
309 | break; | 220 | break; |
310 | } | 221 | } |
311 | up_read(&tomoyo_domain_initializer_list_lock); | ||
312 | return done; | 222 | return done; |
313 | } | 223 | } |
314 | 224 | ||
@@ -320,6 +230,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
320 | * @is_delete: True if it is a delete request. | 230 | * @is_delete: True if it is a delete request. |
321 | * | 231 | * |
322 | * Returns 0 on success, negative value otherwise. | 232 | * Returns 0 on success, negative value otherwise. |
233 | * | ||
234 | * Caller holds tomoyo_read_lock(). | ||
323 | */ | 235 | */ |
324 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 236 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, |
325 | const bool is_delete) | 237 | const bool is_delete) |
@@ -345,6 +257,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | |||
345 | * | 257 | * |
346 | * Returns true if executing @program reinitializes domain transition, | 258 | * Returns true if executing @program reinitializes domain transition, |
347 | * false otherwise. | 259 | * false otherwise. |
260 | * | ||
261 | * Caller holds tomoyo_read_lock(). | ||
348 | */ | 262 | */ |
349 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | 263 | static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * |
350 | domainname, | 264 | domainname, |
@@ -355,8 +269,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
355 | struct tomoyo_domain_initializer_entry *ptr; | 269 | struct tomoyo_domain_initializer_entry *ptr; |
356 | bool flag = false; | 270 | bool flag = false; |
357 | 271 | ||
358 | down_read(&tomoyo_domain_initializer_list_lock); | 272 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { |
359 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | ||
360 | if (ptr->is_deleted) | 273 | if (ptr->is_deleted) |
361 | continue; | 274 | continue; |
362 | if (ptr->domainname) { | 275 | if (ptr->domainname) { |
@@ -376,7 +289,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
376 | } | 289 | } |
377 | flag = true; | 290 | flag = true; |
378 | } | 291 | } |
379 | up_read(&tomoyo_domain_initializer_list_lock); | ||
380 | return flag; | 292 | return flag; |
381 | } | 293 | } |
382 | 294 | ||
@@ -418,8 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | 330 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless |
419 | * explicitly specified by "initialize_domain". | 331 | * explicitly specified by "initialize_domain". |
420 | */ | 332 | */ |
421 | static LIST_HEAD(tomoyo_domain_keeper_list); | 333 | LIST_HEAD(tomoyo_domain_keeper_list); |
422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | ||
423 | 334 | ||
424 | /** | 335 | /** |
425 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | 336 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. |
@@ -430,59 +341,64 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | |||
430 | * @is_delete: True if it is a delete request. | 341 | * @is_delete: True if it is a delete request. |
431 | * | 342 | * |
432 | * Returns 0 on success, negative value otherwise. | 343 | * Returns 0 on success, negative value otherwise. |
344 | * | ||
345 | * Caller holds tomoyo_read_lock(). | ||
433 | */ | 346 | */ |
434 | static int tomoyo_update_domain_keeper_entry(const char *domainname, | 347 | static int tomoyo_update_domain_keeper_entry(const char *domainname, |
435 | const char *program, | 348 | const char *program, |
436 | const bool is_not, | 349 | const bool is_not, |
437 | const bool is_delete) | 350 | const bool is_delete) |
438 | { | 351 | { |
439 | struct tomoyo_domain_keeper_entry *new_entry; | 352 | struct tomoyo_domain_keeper_entry *entry = NULL; |
440 | struct tomoyo_domain_keeper_entry *ptr; | 353 | struct tomoyo_domain_keeper_entry *ptr; |
441 | const struct tomoyo_path_info *saved_domainname; | 354 | const struct tomoyo_path_info *saved_domainname = NULL; |
442 | const struct tomoyo_path_info *saved_program = NULL; | 355 | const struct tomoyo_path_info *saved_program = NULL; |
443 | int error = -ENOMEM; | 356 | int error = is_delete ? -ENOENT : -ENOMEM; |
444 | bool is_last_name = false; | 357 | bool is_last_name = false; |
445 | 358 | ||
446 | if (!tomoyo_is_domain_def(domainname) && | 359 | if (!tomoyo_is_domain_def(domainname) && |
447 | tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) | 360 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
448 | is_last_name = true; | 361 | is_last_name = true; |
449 | else if (!tomoyo_is_correct_domain(domainname, __func__)) | 362 | else if (!tomoyo_is_correct_domain(domainname)) |
450 | return -EINVAL; | 363 | return -EINVAL; |
451 | if (program) { | 364 | if (program) { |
452 | if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) | 365 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
453 | return -EINVAL; | 366 | return -EINVAL; |
454 | saved_program = tomoyo_save_name(program); | 367 | saved_program = tomoyo_get_name(program); |
455 | if (!saved_program) | 368 | if (!saved_program) |
456 | return -ENOMEM; | 369 | goto out; |
457 | } | 370 | } |
458 | saved_domainname = tomoyo_save_name(domainname); | 371 | saved_domainname = tomoyo_get_name(domainname); |
459 | if (!saved_domainname) | 372 | if (!saved_domainname) |
460 | return -ENOMEM; | 373 | goto out; |
461 | down_write(&tomoyo_domain_keeper_list_lock); | 374 | if (!is_delete) |
462 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 375 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
376 | mutex_lock(&tomoyo_policy_lock); | ||
377 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
463 | if (ptr->is_not != is_not || | 378 | if (ptr->is_not != is_not || |
464 | ptr->domainname != saved_domainname || | 379 | ptr->domainname != saved_domainname || |
465 | ptr->program != saved_program) | 380 | ptr->program != saved_program) |
466 | continue; | 381 | continue; |
467 | ptr->is_deleted = is_delete; | 382 | ptr->is_deleted = is_delete; |
468 | error = 0; | 383 | error = 0; |
469 | goto out; | 384 | break; |
470 | } | 385 | } |
471 | if (is_delete) { | 386 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
472 | error = -ENOENT; | 387 | entry->domainname = saved_domainname; |
473 | goto out; | 388 | saved_domainname = NULL; |
389 | entry->program = saved_program; | ||
390 | saved_program = NULL; | ||
391 | entry->is_not = is_not; | ||
392 | entry->is_last_name = is_last_name; | ||
393 | list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); | ||
394 | entry = NULL; | ||
395 | error = 0; | ||
474 | } | 396 | } |
475 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 397 | mutex_unlock(&tomoyo_policy_lock); |
476 | if (!new_entry) | ||
477 | goto out; | ||
478 | new_entry->domainname = saved_domainname; | ||
479 | new_entry->program = saved_program; | ||
480 | new_entry->is_not = is_not; | ||
481 | new_entry->is_last_name = is_last_name; | ||
482 | list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); | ||
483 | error = 0; | ||
484 | out: | 398 | out: |
485 | up_write(&tomoyo_domain_keeper_list_lock); | 399 | tomoyo_put_name(saved_domainname); |
400 | tomoyo_put_name(saved_program); | ||
401 | kfree(entry); | ||
486 | return error; | 402 | return error; |
487 | } | 403 | } |
488 | 404 | ||
@@ -493,6 +409,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
493 | * @is_not: True if it is "no_keep_domain" entry. | 409 | * @is_not: True if it is "no_keep_domain" entry. |
494 | * @is_delete: True if it is a delete request. | 410 | * @is_delete: True if it is a delete request. |
495 | * | 411 | * |
412 | * Caller holds tomoyo_read_lock(). | ||
496 | */ | 413 | */ |
497 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | 414 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, |
498 | const bool is_delete) | 415 | const bool is_delete) |
@@ -513,13 +430,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | |||
513 | * @head: Pointer to "struct tomoyo_io_buffer". | 430 | * @head: Pointer to "struct tomoyo_io_buffer". |
514 | * | 431 | * |
515 | * Returns true on success, false otherwise. | 432 | * Returns true on success, false otherwise. |
433 | * | ||
434 | * Caller holds tomoyo_read_lock(). | ||
516 | */ | 435 | */ |
517 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | 436 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) |
518 | { | 437 | { |
519 | struct list_head *pos; | 438 | struct list_head *pos; |
520 | bool done = true; | 439 | bool done = true; |
521 | 440 | ||
522 | down_read(&tomoyo_domain_keeper_list_lock); | ||
523 | list_for_each_cookie(pos, head->read_var2, | 441 | list_for_each_cookie(pos, head->read_var2, |
524 | &tomoyo_domain_keeper_list) { | 442 | &tomoyo_domain_keeper_list) { |
525 | struct tomoyo_domain_keeper_entry *ptr; | 443 | struct tomoyo_domain_keeper_entry *ptr; |
@@ -542,7 +460,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
542 | if (!done) | 460 | if (!done) |
543 | break; | 461 | break; |
544 | } | 462 | } |
545 | up_read(&tomoyo_domain_keeper_list_lock); | ||
546 | return done; | 463 | return done; |
547 | } | 464 | } |
548 | 465 | ||
@@ -555,6 +472,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
555 | * | 472 | * |
556 | * Returns true if executing @program supresses domain transition, | 473 | * Returns true if executing @program supresses domain transition, |
557 | * false otherwise. | 474 | * false otherwise. |
475 | * | ||
476 | * Caller holds tomoyo_read_lock(). | ||
558 | */ | 477 | */ |
559 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | 478 | static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, |
560 | const struct tomoyo_path_info *program, | 479 | const struct tomoyo_path_info *program, |
@@ -563,8 +482,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
563 | struct tomoyo_domain_keeper_entry *ptr; | 482 | struct tomoyo_domain_keeper_entry *ptr; |
564 | bool flag = false; | 483 | bool flag = false; |
565 | 484 | ||
566 | down_read(&tomoyo_domain_keeper_list_lock); | 485 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { |
567 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | ||
568 | if (ptr->is_deleted) | 486 | if (ptr->is_deleted) |
569 | continue; | 487 | continue; |
570 | if (!ptr->is_last_name) { | 488 | if (!ptr->is_last_name) { |
@@ -582,7 +500,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
582 | } | 500 | } |
583 | flag = true; | 501 | flag = true; |
584 | } | 502 | } |
585 | up_read(&tomoyo_domain_keeper_list_lock); | ||
586 | return flag; | 503 | return flag; |
587 | } | 504 | } |
588 | 505 | ||
@@ -616,8 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
616 | * /bin/busybox and domainname which the current process will belong to after | 533 | * /bin/busybox and domainname which the current process will belong to after |
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | 534 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . |
618 | */ | 535 | */ |
619 | static LIST_HEAD(tomoyo_alias_list); | 536 | LIST_HEAD(tomoyo_alias_list); |
620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | ||
621 | 537 | ||
622 | /** | 538 | /** |
623 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. | 539 | * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. |
@@ -627,46 +543,51 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock); | |||
627 | * @is_delete: True if it is a delete request. | 543 | * @is_delete: True if it is a delete request. |
628 | * | 544 | * |
629 | * Returns 0 on success, negative value otherwise. | 545 | * Returns 0 on success, negative value otherwise. |
546 | * | ||
547 | * Caller holds tomoyo_read_lock(). | ||
630 | */ | 548 | */ |
631 | static int tomoyo_update_alias_entry(const char *original_name, | 549 | static int tomoyo_update_alias_entry(const char *original_name, |
632 | const char *aliased_name, | 550 | const char *aliased_name, |
633 | const bool is_delete) | 551 | const bool is_delete) |
634 | { | 552 | { |
635 | struct tomoyo_alias_entry *new_entry; | 553 | struct tomoyo_alias_entry *entry = NULL; |
636 | struct tomoyo_alias_entry *ptr; | 554 | struct tomoyo_alias_entry *ptr; |
637 | const struct tomoyo_path_info *saved_original_name; | 555 | const struct tomoyo_path_info *saved_original_name; |
638 | const struct tomoyo_path_info *saved_aliased_name; | 556 | const struct tomoyo_path_info *saved_aliased_name; |
639 | int error = -ENOMEM; | 557 | int error = is_delete ? -ENOENT : -ENOMEM; |
640 | 558 | ||
641 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || | 559 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || |
642 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) | 560 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) |
643 | return -EINVAL; /* No patterns allowed. */ | 561 | return -EINVAL; /* No patterns allowed. */ |
644 | saved_original_name = tomoyo_save_name(original_name); | 562 | saved_original_name = tomoyo_get_name(original_name); |
645 | saved_aliased_name = tomoyo_save_name(aliased_name); | 563 | saved_aliased_name = tomoyo_get_name(aliased_name); |
646 | if (!saved_original_name || !saved_aliased_name) | 564 | if (!saved_original_name || !saved_aliased_name) |
647 | return -ENOMEM; | 565 | goto out; |
648 | down_write(&tomoyo_alias_list_lock); | 566 | if (!is_delete) |
649 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 567 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
568 | mutex_lock(&tomoyo_policy_lock); | ||
569 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
650 | if (ptr->original_name != saved_original_name || | 570 | if (ptr->original_name != saved_original_name || |
651 | ptr->aliased_name != saved_aliased_name) | 571 | ptr->aliased_name != saved_aliased_name) |
652 | continue; | 572 | continue; |
653 | ptr->is_deleted = is_delete; | 573 | ptr->is_deleted = is_delete; |
654 | error = 0; | 574 | error = 0; |
655 | goto out; | 575 | break; |
656 | } | 576 | } |
657 | if (is_delete) { | 577 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
658 | error = -ENOENT; | 578 | entry->original_name = saved_original_name; |
659 | goto out; | 579 | saved_original_name = NULL; |
580 | entry->aliased_name = saved_aliased_name; | ||
581 | saved_aliased_name = NULL; | ||
582 | list_add_tail_rcu(&entry->list, &tomoyo_alias_list); | ||
583 | entry = NULL; | ||
584 | error = 0; | ||
660 | } | 585 | } |
661 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 586 | mutex_unlock(&tomoyo_policy_lock); |
662 | if (!new_entry) | ||
663 | goto out; | ||
664 | new_entry->original_name = saved_original_name; | ||
665 | new_entry->aliased_name = saved_aliased_name; | ||
666 | list_add_tail(&new_entry->list, &tomoyo_alias_list); | ||
667 | error = 0; | ||
668 | out: | 587 | out: |
669 | up_write(&tomoyo_alias_list_lock); | 588 | tomoyo_put_name(saved_original_name); |
589 | tomoyo_put_name(saved_aliased_name); | ||
590 | kfree(entry); | ||
670 | return error; | 591 | return error; |
671 | } | 592 | } |
672 | 593 | ||
@@ -676,13 +597,14 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
676 | * @head: Pointer to "struct tomoyo_io_buffer". | 597 | * @head: Pointer to "struct tomoyo_io_buffer". |
677 | * | 598 | * |
678 | * Returns true on success, false otherwise. | 599 | * Returns true on success, false otherwise. |
600 | * | ||
601 | * Caller holds tomoyo_read_lock(). | ||
679 | */ | 602 | */ |
680 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | 603 | bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) |
681 | { | 604 | { |
682 | struct list_head *pos; | 605 | struct list_head *pos; |
683 | bool done = true; | 606 | bool done = true; |
684 | 607 | ||
685 | down_read(&tomoyo_alias_list_lock); | ||
686 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { | 608 | list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { |
687 | struct tomoyo_alias_entry *ptr; | 609 | struct tomoyo_alias_entry *ptr; |
688 | 610 | ||
@@ -695,7 +617,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
695 | if (!done) | 617 | if (!done) |
696 | break; | 618 | break; |
697 | } | 619 | } |
698 | up_read(&tomoyo_alias_list_lock); | ||
699 | return done; | 620 | return done; |
700 | } | 621 | } |
701 | 622 | ||
@@ -706,6 +627,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
706 | * @is_delete: True if it is a delete request. | 627 | * @is_delete: True if it is a delete request. |
707 | * | 628 | * |
708 | * Returns 0 on success, negative value otherwise. | 629 | * Returns 0 on success, negative value otherwise. |
630 | * | ||
631 | * Caller holds tomoyo_read_lock(). | ||
709 | */ | 632 | */ |
710 | int tomoyo_write_alias_policy(char *data, const bool is_delete) | 633 | int tomoyo_write_alias_policy(char *data, const bool is_delete) |
711 | { | 634 | { |
@@ -724,63 +647,46 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) | |||
724 | * @profile: Profile number to assign if the domain was newly created. | 647 | * @profile: Profile number to assign if the domain was newly created. |
725 | * | 648 | * |
726 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | 649 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. |
650 | * | ||
651 | * Caller holds tomoyo_read_lock(). | ||
727 | */ | 652 | */ |
728 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 653 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
729 | domainname, | 654 | domainname, |
730 | const u8 profile) | 655 | const u8 profile) |
731 | { | 656 | { |
732 | struct tomoyo_domain_info *domain = NULL; | 657 | struct tomoyo_domain_info *entry; |
658 | struct tomoyo_domain_info *domain; | ||
733 | const struct tomoyo_path_info *saved_domainname; | 659 | const struct tomoyo_path_info *saved_domainname; |
660 | bool found = false; | ||
734 | 661 | ||
735 | down_write(&tomoyo_domain_list_lock); | 662 | if (!tomoyo_is_correct_domain(domainname)) |
736 | domain = tomoyo_find_domain(domainname); | 663 | return NULL; |
737 | if (domain) | 664 | saved_domainname = tomoyo_get_name(domainname); |
738 | goto out; | ||
739 | if (!tomoyo_is_correct_domain(domainname, __func__)) | ||
740 | goto out; | ||
741 | saved_domainname = tomoyo_save_name(domainname); | ||
742 | if (!saved_domainname) | 665 | if (!saved_domainname) |
743 | goto out; | 666 | return NULL; |
744 | /* Can I reuse memory of deleted domain? */ | 667 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
745 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 668 | mutex_lock(&tomoyo_policy_lock); |
746 | struct task_struct *p; | 669 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
747 | struct tomoyo_acl_info *ptr; | 670 | if (domain->is_deleted || |
748 | bool flag; | 671 | tomoyo_pathcmp(saved_domainname, domain->domainname)) |
749 | if (!domain->is_deleted || | ||
750 | domain->domainname != saved_domainname) | ||
751 | continue; | 672 | continue; |
752 | flag = false; | 673 | found = true; |
753 | read_lock(&tasklist_lock); | 674 | break; |
754 | for_each_process(p) { | ||
755 | if (tomoyo_real_domain(p) != domain) | ||
756 | continue; | ||
757 | flag = true; | ||
758 | break; | ||
759 | } | ||
760 | read_unlock(&tasklist_lock); | ||
761 | if (flag) | ||
762 | continue; | ||
763 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
764 | ptr->type |= TOMOYO_ACL_DELETED; | ||
765 | } | ||
766 | tomoyo_set_domain_flag(domain, true, domain->flags); | ||
767 | domain->profile = profile; | ||
768 | domain->quota_warned = false; | ||
769 | mb(); /* Avoid out-of-order execution. */ | ||
770 | domain->is_deleted = false; | ||
771 | goto out; | ||
772 | } | 675 | } |
773 | /* No memory reusable. Create using new memory. */ | 676 | if (!found && tomoyo_memory_ok(entry)) { |
774 | domain = tomoyo_alloc_element(sizeof(*domain)); | 677 | INIT_LIST_HEAD(&entry->acl_info_list); |
775 | if (domain) { | 678 | entry->domainname = saved_domainname; |
776 | INIT_LIST_HEAD(&domain->acl_info_list); | 679 | saved_domainname = NULL; |
777 | domain->domainname = saved_domainname; | 680 | entry->profile = profile; |
778 | domain->profile = profile; | 681 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); |
779 | list_add_tail(&domain->list, &tomoyo_domain_list); | 682 | domain = entry; |
683 | entry = NULL; | ||
684 | found = true; | ||
780 | } | 685 | } |
781 | out: | 686 | mutex_unlock(&tomoyo_policy_lock); |
782 | up_write(&tomoyo_domain_list_lock); | 687 | tomoyo_put_name(saved_domainname); |
783 | return domain; | 688 | kfree(entry); |
689 | return found ? domain : NULL; | ||
784 | } | 690 | } |
785 | 691 | ||
786 | /** | 692 | /** |
@@ -789,6 +695,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
789 | * @bprm: Pointer to "struct linux_binprm". | 695 | * @bprm: Pointer to "struct linux_binprm". |
790 | * | 696 | * |
791 | * Returns 0 on success, negative value otherwise. | 697 | * Returns 0 on success, negative value otherwise. |
698 | * | ||
699 | * Caller holds tomoyo_read_lock(). | ||
792 | */ | 700 | */ |
793 | int tomoyo_find_next_domain(struct linux_binprm *bprm) | 701 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
794 | { | 702 | { |
@@ -796,7 +704,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
796 | * This function assumes that the size of buffer returned by | 704 | * This function assumes that the size of buffer returned by |
797 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | 705 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. |
798 | */ | 706 | */ |
799 | struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp)); | 707 | struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
800 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 708 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
801 | struct tomoyo_domain_info *domain = NULL; | 709 | struct tomoyo_domain_info *domain = NULL; |
802 | const char *old_domain_name = old_domain->domainname->name; | 710 | const char *old_domain_name = old_domain->domainname->name; |
@@ -849,8 +757,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
849 | if (tomoyo_pathcmp(&r, &s)) { | 757 | if (tomoyo_pathcmp(&r, &s)) { |
850 | struct tomoyo_alias_entry *ptr; | 758 | struct tomoyo_alias_entry *ptr; |
851 | /* Is this program allowed to be called via symbolic links? */ | 759 | /* Is this program allowed to be called via symbolic links? */ |
852 | down_read(&tomoyo_alias_list_lock); | 760 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { |
853 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | ||
854 | if (ptr->is_deleted || | 761 | if (ptr->is_deleted || |
855 | tomoyo_pathcmp(&r, ptr->original_name) || | 762 | tomoyo_pathcmp(&r, ptr->original_name) || |
856 | tomoyo_pathcmp(&s, ptr->aliased_name)) | 763 | tomoyo_pathcmp(&s, ptr->aliased_name)) |
@@ -861,7 +768,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
861 | tomoyo_fill_path_info(&r); | 768 | tomoyo_fill_path_info(&r); |
862 | break; | 769 | break; |
863 | } | 770 | } |
864 | up_read(&tomoyo_alias_list_lock); | ||
865 | } | 771 | } |
866 | 772 | ||
867 | /* Check execute permission. */ | 773 | /* Check execute permission. */ |
@@ -892,9 +798,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
892 | } | 798 | } |
893 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) | 799 | if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) |
894 | goto done; | 800 | goto done; |
895 | down_read(&tomoyo_domain_list_lock); | ||
896 | domain = tomoyo_find_domain(new_domain_name); | 801 | domain = tomoyo_find_domain(new_domain_name); |
897 | up_read(&tomoyo_domain_list_lock); | ||
898 | if (domain) | 802 | if (domain) |
899 | goto done; | 803 | goto done; |
900 | if (is_enforce) | 804 | if (is_enforce) |
@@ -909,14 +813,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
909 | if (is_enforce) | 813 | if (is_enforce) |
910 | retval = -EPERM; | 814 | retval = -EPERM; |
911 | else | 815 | else |
912 | tomoyo_set_domain_flag(old_domain, false, | 816 | old_domain->transition_failed = true; |
913 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | ||
914 | out: | 817 | out: |
915 | if (!domain) | 818 | if (!domain) |
916 | domain = old_domain; | 819 | domain = old_domain; |
820 | /* Update reference count on "struct tomoyo_domain_info". */ | ||
821 | atomic_inc(&domain->users); | ||
917 | bprm->cred->security = domain; | 822 | bprm->cred->security = domain; |
918 | tomoyo_free(real_program_name); | 823 | kfree(real_program_name); |
919 | tomoyo_free(symlink_program_name); | 824 | kfree(symlink_program_name); |
920 | tomoyo_free(tmp); | 825 | kfree(tmp); |
921 | return retval; | 826 | return retval; |
922 | } | 827 | } |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 9a6c58881c0a..1b24304edb7d 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -10,108 +10,64 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | ||
14 | #include "realpath.h" | ||
15 | |||
16 | /* | ||
17 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
18 | * "allow_read" entries. | ||
19 | * It has following fields. | ||
20 | * | ||
21 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
22 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
23 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
24 | * otherwise. | ||
25 | */ | ||
26 | struct tomoyo_globally_readable_file_entry { | ||
27 | struct list_head list; | ||
28 | const struct tomoyo_path_info *filename; | ||
29 | bool is_deleted; | ||
30 | }; | ||
31 | |||
32 | /* | ||
33 | * tomoyo_pattern_entry is a structure which is used for holding | ||
34 | * "tomoyo_pattern_list" entries. | ||
35 | * It has following fields. | ||
36 | * | ||
37 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
38 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
39 | * to pathname patterns during learning mode. | ||
40 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
41 | * otherwise. | ||
42 | */ | ||
43 | struct tomoyo_pattern_entry { | ||
44 | struct list_head list; | ||
45 | const struct tomoyo_path_info *pattern; | ||
46 | bool is_deleted; | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
51 | * "deny_rewrite" entries. | ||
52 | * It has following fields. | ||
53 | * | ||
54 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
55 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
56 | * already existing content. | ||
57 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
58 | * otherwise. | ||
59 | */ | ||
60 | struct tomoyo_no_rewrite_entry { | ||
61 | struct list_head list; | ||
62 | const struct tomoyo_path_info *pattern; | ||
63 | bool is_deleted; | ||
64 | }; | ||
65 | 13 | ||
66 | /* Keyword array for single path operations. */ | 14 | /* Keyword array for single path operations. */ |
67 | static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { | 15 | static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
68 | [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", | 16 | [TOMOYO_TYPE_READ_WRITE] = "read/write", |
69 | [TOMOYO_TYPE_EXECUTE_ACL] = "execute", | 17 | [TOMOYO_TYPE_EXECUTE] = "execute", |
70 | [TOMOYO_TYPE_READ_ACL] = "read", | 18 | [TOMOYO_TYPE_READ] = "read", |
71 | [TOMOYO_TYPE_WRITE_ACL] = "write", | 19 | [TOMOYO_TYPE_WRITE] = "write", |
72 | [TOMOYO_TYPE_CREATE_ACL] = "create", | 20 | [TOMOYO_TYPE_CREATE] = "create", |
73 | [TOMOYO_TYPE_UNLINK_ACL] = "unlink", | 21 | [TOMOYO_TYPE_UNLINK] = "unlink", |
74 | [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", | 22 | [TOMOYO_TYPE_MKDIR] = "mkdir", |
75 | [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", | 23 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
76 | [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", | 24 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", |
77 | [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", | 25 | [TOMOYO_TYPE_MKSOCK] = "mksock", |
78 | [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", | 26 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", |
79 | [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", | 27 | [TOMOYO_TYPE_MKCHAR] = "mkchar", |
80 | [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", | 28 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
81 | [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", | 29 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
82 | [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", | 30 | [TOMOYO_TYPE_REWRITE] = "rewrite", |
31 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
32 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
33 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
34 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
35 | [TOMOYO_TYPE_CHROOT] = "chroot", | ||
36 | [TOMOYO_TYPE_MOUNT] = "mount", | ||
37 | [TOMOYO_TYPE_UMOUNT] = "unmount", | ||
83 | }; | 38 | }; |
84 | 39 | ||
85 | /* Keyword array for double path operations. */ | 40 | /* Keyword array for double path operations. */ |
86 | static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { | 41 | static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { |
87 | [TOMOYO_TYPE_LINK_ACL] = "link", | 42 | [TOMOYO_TYPE_LINK] = "link", |
88 | [TOMOYO_TYPE_RENAME_ACL] = "rename", | 43 | [TOMOYO_TYPE_RENAME] = "rename", |
44 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | ||
89 | }; | 45 | }; |
90 | 46 | ||
91 | /** | 47 | /** |
92 | * tomoyo_sp2keyword - Get the name of single path operation. | 48 | * tomoyo_path2keyword - Get the name of single path operation. |
93 | * | 49 | * |
94 | * @operation: Type of operation. | 50 | * @operation: Type of operation. |
95 | * | 51 | * |
96 | * Returns the name of single path operation. | 52 | * Returns the name of single path operation. |
97 | */ | 53 | */ |
98 | const char *tomoyo_sp2keyword(const u8 operation) | 54 | const char *tomoyo_path2keyword(const u8 operation) |
99 | { | 55 | { |
100 | return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) | 56 | return (operation < TOMOYO_MAX_PATH_OPERATION) |
101 | ? tomoyo_sp_keyword[operation] : NULL; | 57 | ? tomoyo_path_keyword[operation] : NULL; |
102 | } | 58 | } |
103 | 59 | ||
104 | /** | 60 | /** |
105 | * tomoyo_dp2keyword - Get the name of double path operation. | 61 | * tomoyo_path22keyword - Get the name of double path operation. |
106 | * | 62 | * |
107 | * @operation: Type of operation. | 63 | * @operation: Type of operation. |
108 | * | 64 | * |
109 | * Returns the name of double path operation. | 65 | * Returns the name of double path operation. |
110 | */ | 66 | */ |
111 | const char *tomoyo_dp2keyword(const u8 operation) | 67 | const char *tomoyo_path22keyword(const u8 operation) |
112 | { | 68 | { |
113 | return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) | 69 | return (operation < TOMOYO_MAX_PATH2_OPERATION) |
114 | ? tomoyo_dp_keyword[operation] : NULL; | 70 | ? tomoyo_path2_keyword[operation] : NULL; |
115 | } | 71 | } |
116 | 72 | ||
117 | /** | 73 | /** |
@@ -142,7 +98,8 @@ static bool tomoyo_strendswith(const char *name, const char *tail) | |||
142 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | 98 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) |
143 | { | 99 | { |
144 | int error; | 100 | int error; |
145 | struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); | 101 | struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), |
102 | GFP_KERNEL); | ||
146 | 103 | ||
147 | if (!buf) | 104 | if (!buf) |
148 | return NULL; | 105 | return NULL; |
@@ -154,20 +111,17 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | |||
154 | tomoyo_fill_path_info(&buf->head); | 111 | tomoyo_fill_path_info(&buf->head); |
155 | return &buf->head; | 112 | return &buf->head; |
156 | } | 113 | } |
157 | tomoyo_free(buf); | 114 | kfree(buf); |
158 | return NULL; | 115 | return NULL; |
159 | } | 116 | } |
160 | 117 | ||
161 | /* Lock for domain->acl_info_list. */ | 118 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
162 | DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); | 119 | const char *filename2, |
163 | 120 | struct tomoyo_domain_info *const domain, | |
164 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 121 | const bool is_delete); |
165 | const char *filename2, | 122 | static int tomoyo_update_path_acl(const u8 type, const char *filename, |
166 | struct tomoyo_domain_info * | 123 | struct tomoyo_domain_info *const domain, |
167 | const domain, const bool is_delete); | 124 | const bool is_delete); |
168 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | ||
169 | struct tomoyo_domain_info * | ||
170 | const domain, const bool is_delete); | ||
171 | 125 | ||
172 | /* | 126 | /* |
173 | * tomoyo_globally_readable_list is used for holding list of pathnames which | 127 | * tomoyo_globally_readable_list is used for holding list of pathnames which |
@@ -194,8 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
194 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | 148 | * given "allow_read /lib/libc-2.5.so" to the domain which current process |
195 | * belongs to. | 149 | * belongs to. |
196 | */ | 150 | */ |
197 | static LIST_HEAD(tomoyo_globally_readable_list); | 151 | LIST_HEAD(tomoyo_globally_readable_list); |
198 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | ||
199 | 152 | ||
200 | /** | 153 | /** |
201 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. | 154 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. |
@@ -204,40 +157,42 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | |||
204 | * @is_delete: True if it is a delete request. | 157 | * @is_delete: True if it is a delete request. |
205 | * | 158 | * |
206 | * Returns 0 on success, negative value otherwise. | 159 | * Returns 0 on success, negative value otherwise. |
160 | * | ||
161 | * Caller holds tomoyo_read_lock(). | ||
207 | */ | 162 | */ |
208 | static int tomoyo_update_globally_readable_entry(const char *filename, | 163 | static int tomoyo_update_globally_readable_entry(const char *filename, |
209 | const bool is_delete) | 164 | const bool is_delete) |
210 | { | 165 | { |
211 | struct tomoyo_globally_readable_file_entry *new_entry; | 166 | struct tomoyo_globally_readable_file_entry *entry = NULL; |
212 | struct tomoyo_globally_readable_file_entry *ptr; | 167 | struct tomoyo_globally_readable_file_entry *ptr; |
213 | const struct tomoyo_path_info *saved_filename; | 168 | const struct tomoyo_path_info *saved_filename; |
214 | int error = -ENOMEM; | 169 | int error = is_delete ? -ENOENT : -ENOMEM; |
215 | 170 | ||
216 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) | 171 | if (!tomoyo_is_correct_path(filename, 1, 0, -1)) |
217 | return -EINVAL; | 172 | return -EINVAL; |
218 | saved_filename = tomoyo_save_name(filename); | 173 | saved_filename = tomoyo_get_name(filename); |
219 | if (!saved_filename) | 174 | if (!saved_filename) |
220 | return -ENOMEM; | 175 | return -ENOMEM; |
221 | down_write(&tomoyo_globally_readable_list_lock); | 176 | if (!is_delete) |
222 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 177 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
178 | mutex_lock(&tomoyo_policy_lock); | ||
179 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { | ||
223 | if (ptr->filename != saved_filename) | 180 | if (ptr->filename != saved_filename) |
224 | continue; | 181 | continue; |
225 | ptr->is_deleted = is_delete; | 182 | ptr->is_deleted = is_delete; |
226 | error = 0; | 183 | error = 0; |
227 | goto out; | 184 | break; |
228 | } | 185 | } |
229 | if (is_delete) { | 186 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
230 | error = -ENOENT; | 187 | entry->filename = saved_filename; |
231 | goto out; | 188 | saved_filename = NULL; |
189 | list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); | ||
190 | entry = NULL; | ||
191 | error = 0; | ||
232 | } | 192 | } |
233 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 193 | mutex_unlock(&tomoyo_policy_lock); |
234 | if (!new_entry) | 194 | tomoyo_put_name(saved_filename); |
235 | goto out; | 195 | kfree(entry); |
236 | new_entry->filename = saved_filename; | ||
237 | list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); | ||
238 | error = 0; | ||
239 | out: | ||
240 | up_write(&tomoyo_globally_readable_list_lock); | ||
241 | return error; | 196 | return error; |
242 | } | 197 | } |
243 | 198 | ||
@@ -247,21 +202,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
247 | * @filename: The filename to check. | 202 | * @filename: The filename to check. |
248 | * | 203 | * |
249 | * Returns true if any domain can open @filename for reading, false otherwise. | 204 | * Returns true if any domain can open @filename for reading, false otherwise. |
205 | * | ||
206 | * Caller holds tomoyo_read_lock(). | ||
250 | */ | 207 | */ |
251 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | 208 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * |
252 | filename) | 209 | filename) |
253 | { | 210 | { |
254 | struct tomoyo_globally_readable_file_entry *ptr; | 211 | struct tomoyo_globally_readable_file_entry *ptr; |
255 | bool found = false; | 212 | bool found = false; |
256 | down_read(&tomoyo_globally_readable_list_lock); | 213 | |
257 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 214 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { |
258 | if (!ptr->is_deleted && | 215 | if (!ptr->is_deleted && |
259 | tomoyo_path_matches_pattern(filename, ptr->filename)) { | 216 | tomoyo_path_matches_pattern(filename, ptr->filename)) { |
260 | found = true; | 217 | found = true; |
261 | break; | 218 | break; |
262 | } | 219 | } |
263 | } | 220 | } |
264 | up_read(&tomoyo_globally_readable_list_lock); | ||
265 | return found; | 221 | return found; |
266 | } | 222 | } |
267 | 223 | ||
@@ -272,6 +228,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | |||
272 | * @is_delete: True if it is a delete request. | 228 | * @is_delete: True if it is a delete request. |
273 | * | 229 | * |
274 | * Returns 0 on success, negative value otherwise. | 230 | * Returns 0 on success, negative value otherwise. |
231 | * | ||
232 | * Caller holds tomoyo_read_lock(). | ||
275 | */ | 233 | */ |
276 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | 234 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) |
277 | { | 235 | { |
@@ -284,13 +242,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | |||
284 | * @head: Pointer to "struct tomoyo_io_buffer". | 242 | * @head: Pointer to "struct tomoyo_io_buffer". |
285 | * | 243 | * |
286 | * Returns true on success, false otherwise. | 244 | * Returns true on success, false otherwise. |
245 | * | ||
246 | * Caller holds tomoyo_read_lock(). | ||
287 | */ | 247 | */ |
288 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | 248 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) |
289 | { | 249 | { |
290 | struct list_head *pos; | 250 | struct list_head *pos; |
291 | bool done = true; | 251 | bool done = true; |
292 | 252 | ||
293 | down_read(&tomoyo_globally_readable_list_lock); | ||
294 | list_for_each_cookie(pos, head->read_var2, | 253 | list_for_each_cookie(pos, head->read_var2, |
295 | &tomoyo_globally_readable_list) { | 254 | &tomoyo_globally_readable_list) { |
296 | struct tomoyo_globally_readable_file_entry *ptr; | 255 | struct tomoyo_globally_readable_file_entry *ptr; |
@@ -304,7 +263,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
304 | if (!done) | 263 | if (!done) |
305 | break; | 264 | break; |
306 | } | 265 | } |
307 | up_read(&tomoyo_globally_readable_list_lock); | ||
308 | return done; | 266 | return done; |
309 | } | 267 | } |
310 | 268 | ||
@@ -337,8 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
337 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | 295 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid |
338 | * current process from accessing other process's information. | 296 | * current process from accessing other process's information. |
339 | */ | 297 | */ |
340 | static LIST_HEAD(tomoyo_pattern_list); | 298 | LIST_HEAD(tomoyo_pattern_list); |
341 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | ||
342 | 299 | ||
343 | /** | 300 | /** |
344 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. | 301 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. |
@@ -347,40 +304,43 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock); | |||
347 | * @is_delete: True if it is a delete request. | 304 | * @is_delete: True if it is a delete request. |
348 | * | 305 | * |
349 | * Returns 0 on success, negative value otherwise. | 306 | * Returns 0 on success, negative value otherwise. |
307 | * | ||
308 | * Caller holds tomoyo_read_lock(). | ||
350 | */ | 309 | */ |
351 | static int tomoyo_update_file_pattern_entry(const char *pattern, | 310 | static int tomoyo_update_file_pattern_entry(const char *pattern, |
352 | const bool is_delete) | 311 | const bool is_delete) |
353 | { | 312 | { |
354 | struct tomoyo_pattern_entry *new_entry; | 313 | struct tomoyo_pattern_entry *entry = NULL; |
355 | struct tomoyo_pattern_entry *ptr; | 314 | struct tomoyo_pattern_entry *ptr; |
356 | const struct tomoyo_path_info *saved_pattern; | 315 | const struct tomoyo_path_info *saved_pattern; |
357 | int error = -ENOMEM; | 316 | int error = is_delete ? -ENOENT : -ENOMEM; |
358 | 317 | ||
359 | if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) | 318 | saved_pattern = tomoyo_get_name(pattern); |
360 | return -EINVAL; | ||
361 | saved_pattern = tomoyo_save_name(pattern); | ||
362 | if (!saved_pattern) | 319 | if (!saved_pattern) |
363 | return -ENOMEM; | 320 | return error; |
364 | down_write(&tomoyo_pattern_list_lock); | 321 | if (!saved_pattern->is_patterned) |
365 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 322 | goto out; |
323 | if (!is_delete) | ||
324 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
325 | mutex_lock(&tomoyo_policy_lock); | ||
326 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
366 | if (saved_pattern != ptr->pattern) | 327 | if (saved_pattern != ptr->pattern) |
367 | continue; | 328 | continue; |
368 | ptr->is_deleted = is_delete; | 329 | ptr->is_deleted = is_delete; |
369 | error = 0; | 330 | error = 0; |
370 | goto out; | 331 | break; |
371 | } | 332 | } |
372 | if (is_delete) { | 333 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
373 | error = -ENOENT; | 334 | entry->pattern = saved_pattern; |
374 | goto out; | 335 | saved_pattern = NULL; |
336 | list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); | ||
337 | entry = NULL; | ||
338 | error = 0; | ||
375 | } | 339 | } |
376 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 340 | mutex_unlock(&tomoyo_policy_lock); |
377 | if (!new_entry) | ||
378 | goto out; | ||
379 | new_entry->pattern = saved_pattern; | ||
380 | list_add_tail(&new_entry->list, &tomoyo_pattern_list); | ||
381 | error = 0; | ||
382 | out: | 341 | out: |
383 | up_write(&tomoyo_pattern_list_lock); | 342 | kfree(entry); |
343 | tomoyo_put_name(saved_pattern); | ||
384 | return error; | 344 | return error; |
385 | } | 345 | } |
386 | 346 | ||
@@ -390,6 +350,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
390 | * @filename: The filename to find patterned pathname. | 350 | * @filename: The filename to find patterned pathname. |
391 | * | 351 | * |
392 | * Returns pointer to pathname pattern if matched, @filename otherwise. | 352 | * Returns pointer to pathname pattern if matched, @filename otherwise. |
353 | * | ||
354 | * Caller holds tomoyo_read_lock(). | ||
393 | */ | 355 | */ |
394 | static const struct tomoyo_path_info * | 356 | static const struct tomoyo_path_info * |
395 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | 357 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) |
@@ -397,8 +359,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
397 | struct tomoyo_pattern_entry *ptr; | 359 | struct tomoyo_pattern_entry *ptr; |
398 | const struct tomoyo_path_info *pattern = NULL; | 360 | const struct tomoyo_path_info *pattern = NULL; |
399 | 361 | ||
400 | down_read(&tomoyo_pattern_list_lock); | 362 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { |
401 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | ||
402 | if (ptr->is_deleted) | 363 | if (ptr->is_deleted) |
403 | continue; | 364 | continue; |
404 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 365 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
@@ -411,7 +372,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
411 | break; | 372 | break; |
412 | } | 373 | } |
413 | } | 374 | } |
414 | up_read(&tomoyo_pattern_list_lock); | ||
415 | if (pattern) | 375 | if (pattern) |
416 | filename = pattern; | 376 | filename = pattern; |
417 | return filename; | 377 | return filename; |
@@ -424,6 +384,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
424 | * @is_delete: True if it is a delete request. | 384 | * @is_delete: True if it is a delete request. |
425 | * | 385 | * |
426 | * Returns 0 on success, negative value otherwise. | 386 | * Returns 0 on success, negative value otherwise. |
387 | * | ||
388 | * Caller holds tomoyo_read_lock(). | ||
427 | */ | 389 | */ |
428 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) | 390 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) |
429 | { | 391 | { |
@@ -436,13 +398,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete) | |||
436 | * @head: Pointer to "struct tomoyo_io_buffer". | 398 | * @head: Pointer to "struct tomoyo_io_buffer". |
437 | * | 399 | * |
438 | * Returns true on success, false otherwise. | 400 | * Returns true on success, false otherwise. |
401 | * | ||
402 | * Caller holds tomoyo_read_lock(). | ||
439 | */ | 403 | */ |
440 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | 404 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) |
441 | { | 405 | { |
442 | struct list_head *pos; | 406 | struct list_head *pos; |
443 | bool done = true; | 407 | bool done = true; |
444 | 408 | ||
445 | down_read(&tomoyo_pattern_list_lock); | ||
446 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { | 409 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { |
447 | struct tomoyo_pattern_entry *ptr; | 410 | struct tomoyo_pattern_entry *ptr; |
448 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); | 411 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); |
@@ -453,7 +416,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
453 | if (!done) | 416 | if (!done) |
454 | break; | 417 | break; |
455 | } | 418 | } |
456 | up_read(&tomoyo_pattern_list_lock); | ||
457 | return done; | 419 | return done; |
458 | } | 420 | } |
459 | 421 | ||
@@ -486,8 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
486 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | 448 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't |
487 | * need to worry whether the file is already unlink()ed or not. | 449 | * need to worry whether the file is already unlink()ed or not. |
488 | */ | 450 | */ |
489 | static LIST_HEAD(tomoyo_no_rewrite_list); | 451 | LIST_HEAD(tomoyo_no_rewrite_list); |
490 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | ||
491 | 452 | ||
492 | /** | 453 | /** |
493 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. | 454 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. |
@@ -496,39 +457,42 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | |||
496 | * @is_delete: True if it is a delete request. | 457 | * @is_delete: True if it is a delete request. |
497 | * | 458 | * |
498 | * Returns 0 on success, negative value otherwise. | 459 | * Returns 0 on success, negative value otherwise. |
460 | * | ||
461 | * Caller holds tomoyo_read_lock(). | ||
499 | */ | 462 | */ |
500 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | 463 | static int tomoyo_update_no_rewrite_entry(const char *pattern, |
501 | const bool is_delete) | 464 | const bool is_delete) |
502 | { | 465 | { |
503 | struct tomoyo_no_rewrite_entry *new_entry, *ptr; | 466 | struct tomoyo_no_rewrite_entry *entry = NULL; |
467 | struct tomoyo_no_rewrite_entry *ptr; | ||
504 | const struct tomoyo_path_info *saved_pattern; | 468 | const struct tomoyo_path_info *saved_pattern; |
505 | int error = -ENOMEM; | 469 | int error = is_delete ? -ENOENT : -ENOMEM; |
506 | 470 | ||
507 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) | 471 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) |
508 | return -EINVAL; | 472 | return -EINVAL; |
509 | saved_pattern = tomoyo_save_name(pattern); | 473 | saved_pattern = tomoyo_get_name(pattern); |
510 | if (!saved_pattern) | 474 | if (!saved_pattern) |
511 | return -ENOMEM; | 475 | return error; |
512 | down_write(&tomoyo_no_rewrite_list_lock); | 476 | if (!is_delete) |
513 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 477 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
478 | mutex_lock(&tomoyo_policy_lock); | ||
479 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
514 | if (ptr->pattern != saved_pattern) | 480 | if (ptr->pattern != saved_pattern) |
515 | continue; | 481 | continue; |
516 | ptr->is_deleted = is_delete; | 482 | ptr->is_deleted = is_delete; |
517 | error = 0; | 483 | error = 0; |
518 | goto out; | 484 | break; |
519 | } | 485 | } |
520 | if (is_delete) { | 486 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
521 | error = -ENOENT; | 487 | entry->pattern = saved_pattern; |
522 | goto out; | 488 | saved_pattern = NULL; |
489 | list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); | ||
490 | entry = NULL; | ||
491 | error = 0; | ||
523 | } | 492 | } |
524 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 493 | mutex_unlock(&tomoyo_policy_lock); |
525 | if (!new_entry) | 494 | tomoyo_put_name(saved_pattern); |
526 | goto out; | 495 | kfree(entry); |
527 | new_entry->pattern = saved_pattern; | ||
528 | list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); | ||
529 | error = 0; | ||
530 | out: | ||
531 | up_write(&tomoyo_no_rewrite_list_lock); | ||
532 | return error; | 496 | return error; |
533 | } | 497 | } |
534 | 498 | ||
@@ -539,14 +503,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
539 | * | 503 | * |
540 | * Returns true if @filename is specified by "deny_rewrite" directive, | 504 | * Returns true if @filename is specified by "deny_rewrite" directive, |
541 | * false otherwise. | 505 | * false otherwise. |
506 | * | ||
507 | * Caller holds tomoyo_read_lock(). | ||
542 | */ | 508 | */ |
543 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | 509 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) |
544 | { | 510 | { |
545 | struct tomoyo_no_rewrite_entry *ptr; | 511 | struct tomoyo_no_rewrite_entry *ptr; |
546 | bool found = false; | 512 | bool found = false; |
547 | 513 | ||
548 | down_read(&tomoyo_no_rewrite_list_lock); | 514 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { |
549 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | ||
550 | if (ptr->is_deleted) | 515 | if (ptr->is_deleted) |
551 | continue; | 516 | continue; |
552 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 517 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
@@ -554,7 +519,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | |||
554 | found = true; | 519 | found = true; |
555 | break; | 520 | break; |
556 | } | 521 | } |
557 | up_read(&tomoyo_no_rewrite_list_lock); | ||
558 | return found; | 522 | return found; |
559 | } | 523 | } |
560 | 524 | ||
@@ -565,6 +529,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | |||
565 | * @is_delete: True if it is a delete request. | 529 | * @is_delete: True if it is a delete request. |
566 | * | 530 | * |
567 | * Returns 0 on success, negative value otherwise. | 531 | * Returns 0 on success, negative value otherwise. |
532 | * | ||
533 | * Caller holds tomoyo_read_lock(). | ||
568 | */ | 534 | */ |
569 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | 535 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) |
570 | { | 536 | { |
@@ -577,13 +543,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | |||
577 | * @head: Pointer to "struct tomoyo_io_buffer". | 543 | * @head: Pointer to "struct tomoyo_io_buffer". |
578 | * | 544 | * |
579 | * Returns true on success, false otherwise. | 545 | * Returns true on success, false otherwise. |
546 | * | ||
547 | * Caller holds tomoyo_read_lock(). | ||
580 | */ | 548 | */ |
581 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | 549 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) |
582 | { | 550 | { |
583 | struct list_head *pos; | 551 | struct list_head *pos; |
584 | bool done = true; | 552 | bool done = true; |
585 | 553 | ||
586 | down_read(&tomoyo_no_rewrite_list_lock); | ||
587 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { | 554 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { |
588 | struct tomoyo_no_rewrite_entry *ptr; | 555 | struct tomoyo_no_rewrite_entry *ptr; |
589 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); | 556 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); |
@@ -594,7 +561,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
594 | if (!done) | 561 | if (!done) |
595 | break; | 562 | break; |
596 | } | 563 | } |
597 | up_read(&tomoyo_no_rewrite_list_lock); | ||
598 | return done; | 564 | return done; |
599 | } | 565 | } |
600 | 566 | ||
@@ -612,6 +578,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
612 | * Current policy syntax uses "allow_read/write" instead of "6", | 578 | * Current policy syntax uses "allow_read/write" instead of "6", |
613 | * "allow_read" instead of "4", "allow_write" instead of "2", | 579 | * "allow_read" instead of "4", "allow_write" instead of "2", |
614 | * "allow_execute" instead of "1". | 580 | * "allow_execute" instead of "1". |
581 | * | ||
582 | * Caller holds tomoyo_read_lock(). | ||
615 | */ | 583 | */ |
616 | static int tomoyo_update_file_acl(const char *filename, u8 perm, | 584 | static int tomoyo_update_file_acl(const char *filename, u8 perm, |
617 | struct tomoyo_domain_info * const domain, | 585 | struct tomoyo_domain_info * const domain, |
@@ -629,19 +597,19 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, | |||
629 | */ | 597 | */ |
630 | return 0; | 598 | return 0; |
631 | if (perm & 4) | 599 | if (perm & 4) |
632 | tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, | 600 | tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, |
633 | domain, is_delete); | 601 | is_delete); |
634 | if (perm & 2) | 602 | if (perm & 2) |
635 | tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, | 603 | tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, |
636 | domain, is_delete); | 604 | is_delete); |
637 | if (perm & 1) | 605 | if (perm & 1) |
638 | tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, | 606 | tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, |
639 | filename, domain, is_delete); | 607 | is_delete); |
640 | return 0; | 608 | return 0; |
641 | } | 609 | } |
642 | 610 | ||
643 | /** | 611 | /** |
644 | * tomoyo_check_single_path_acl2 - Check permission for single path operation. | 612 | * tomoyo_path_acl2 - Check permission for single path operation. |
645 | * | 613 | * |
646 | * @domain: Pointer to "struct tomoyo_domain_info". | 614 | * @domain: Pointer to "struct tomoyo_domain_info". |
647 | * @filename: Filename to check. | 615 | * @filename: Filename to check. |
@@ -649,26 +617,28 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, | |||
649 | * @may_use_pattern: True if patterned ACL is permitted. | 617 | * @may_use_pattern: True if patterned ACL is permitted. |
650 | * | 618 | * |
651 | * Returns 0 on success, -EPERM otherwise. | 619 | * Returns 0 on success, -EPERM otherwise. |
620 | * | ||
621 | * Caller holds tomoyo_read_lock(). | ||
652 | */ | 622 | */ |
653 | static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | 623 | static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, |
654 | domain, | 624 | const struct tomoyo_path_info *filename, |
655 | const struct tomoyo_path_info * | 625 | const u32 perm, const bool may_use_pattern) |
656 | filename, | ||
657 | const u16 perm, | ||
658 | const bool may_use_pattern) | ||
659 | { | 626 | { |
660 | struct tomoyo_acl_info *ptr; | 627 | struct tomoyo_acl_info *ptr; |
661 | int error = -EPERM; | 628 | int error = -EPERM; |
662 | 629 | ||
663 | down_read(&tomoyo_domain_acl_info_list_lock); | 630 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
664 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 631 | struct tomoyo_path_acl *acl; |
665 | struct tomoyo_single_path_acl_record *acl; | 632 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) |
666 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
667 | continue; | ||
668 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
669 | head); | ||
670 | if (!(acl->perm & perm)) | ||
671 | continue; | 633 | continue; |
634 | acl = container_of(ptr, struct tomoyo_path_acl, head); | ||
635 | if (perm <= 0xFFFF) { | ||
636 | if (!(acl->perm & perm)) | ||
637 | continue; | ||
638 | } else { | ||
639 | if (!(acl->perm_high & (perm >> 16))) | ||
640 | continue; | ||
641 | } | ||
672 | if (may_use_pattern || !acl->filename->is_patterned) { | 642 | if (may_use_pattern || !acl->filename->is_patterned) { |
673 | if (!tomoyo_path_matches_pattern(filename, | 643 | if (!tomoyo_path_matches_pattern(filename, |
674 | acl->filename)) | 644 | acl->filename)) |
@@ -679,7 +649,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | |||
679 | error = 0; | 649 | error = 0; |
680 | break; | 650 | break; |
681 | } | 651 | } |
682 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
683 | return error; | 652 | return error; |
684 | } | 653 | } |
685 | 654 | ||
@@ -691,27 +660,28 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | |||
691 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). | 660 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). |
692 | * | 661 | * |
693 | * Returns 0 on success, -EPERM otherwise. | 662 | * Returns 0 on success, -EPERM otherwise. |
663 | * | ||
664 | * Caller holds tomoyo_read_lock(). | ||
694 | */ | 665 | */ |
695 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | 666 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, |
696 | const struct tomoyo_path_info *filename, | 667 | const struct tomoyo_path_info *filename, |
697 | const u8 operation) | 668 | const u8 operation) |
698 | { | 669 | { |
699 | u16 perm = 0; | 670 | u32 perm = 0; |
700 | 671 | ||
701 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 672 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
702 | return 0; | 673 | return 0; |
703 | if (operation == 6) | 674 | if (operation == 6) |
704 | perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 675 | perm = 1 << TOMOYO_TYPE_READ_WRITE; |
705 | else if (operation == 4) | 676 | else if (operation == 4) |
706 | perm = 1 << TOMOYO_TYPE_READ_ACL; | 677 | perm = 1 << TOMOYO_TYPE_READ; |
707 | else if (operation == 2) | 678 | else if (operation == 2) |
708 | perm = 1 << TOMOYO_TYPE_WRITE_ACL; | 679 | perm = 1 << TOMOYO_TYPE_WRITE; |
709 | else if (operation == 1) | 680 | else if (operation == 1) |
710 | perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; | 681 | perm = 1 << TOMOYO_TYPE_EXECUTE; |
711 | else | 682 | else |
712 | BUG(); | 683 | BUG(); |
713 | return tomoyo_check_single_path_acl2(domain, filename, perm, | 684 | return tomoyo_path_acl2(domain, filename, perm, operation != 1); |
714 | operation != 1); | ||
715 | } | 685 | } |
716 | 686 | ||
717 | /** | 687 | /** |
@@ -724,6 +694,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | |||
724 | * @mode: Access control mode. | 694 | * @mode: Access control mode. |
725 | * | 695 | * |
726 | * Returns 0 on success, negative value otherwise. | 696 | * Returns 0 on success, negative value otherwise. |
697 | * | ||
698 | * Caller holds tomoyo_read_lock(). | ||
727 | */ | 699 | */ |
728 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | 700 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, |
729 | const struct tomoyo_path_info *filename, | 701 | const struct tomoyo_path_info *filename, |
@@ -737,18 +709,17 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | |||
737 | if (!filename) | 709 | if (!filename) |
738 | return 0; | 710 | return 0; |
739 | error = tomoyo_check_file_acl(domain, filename, perm); | 711 | error = tomoyo_check_file_acl(domain, filename, perm); |
740 | if (error && perm == 4 && | 712 | if (error && perm == 4 && !domain->ignore_global_allow_read |
741 | (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 | ||
742 | && tomoyo_is_globally_readable_file(filename)) | 713 | && tomoyo_is_globally_readable_file(filename)) |
743 | error = 0; | 714 | error = 0; |
744 | if (perm == 6) | 715 | if (perm == 6) |
745 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); | 716 | msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); |
746 | else if (perm == 4) | 717 | else if (perm == 4) |
747 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); | 718 | msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); |
748 | else if (perm == 2) | 719 | else if (perm == 2) |
749 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); | 720 | msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); |
750 | else if (perm == 1) | 721 | else if (perm == 1) |
751 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); | 722 | msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); |
752 | else | 723 | else |
753 | BUG(); | 724 | BUG(); |
754 | if (!error) | 725 | if (!error) |
@@ -777,6 +748,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | |||
777 | * @is_delete: True if it is a delete request. | 748 | * @is_delete: True if it is a delete request. |
778 | * | 749 | * |
779 | * Returns 0 on success, negative value otherwise. | 750 | * Returns 0 on success, negative value otherwise. |
751 | * | ||
752 | * Caller holds tomoyo_read_lock(). | ||
780 | */ | 753 | */ |
781 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | 754 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, |
782 | const bool is_delete) | 755 | const bool is_delete) |
@@ -795,28 +768,28 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
795 | if (strncmp(data, "allow_", 6)) | 768 | if (strncmp(data, "allow_", 6)) |
796 | goto out; | 769 | goto out; |
797 | data += 6; | 770 | data += 6; |
798 | for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { | 771 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { |
799 | if (strcmp(data, tomoyo_sp_keyword[type])) | 772 | if (strcmp(data, tomoyo_path_keyword[type])) |
800 | continue; | 773 | continue; |
801 | return tomoyo_update_single_path_acl(type, filename, | 774 | return tomoyo_update_path_acl(type, filename, domain, |
802 | domain, is_delete); | 775 | is_delete); |
803 | } | 776 | } |
804 | filename2 = strchr(filename, ' '); | 777 | filename2 = strchr(filename, ' '); |
805 | if (!filename2) | 778 | if (!filename2) |
806 | goto out; | 779 | goto out; |
807 | *filename2++ = '\0'; | 780 | *filename2++ = '\0'; |
808 | for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { | 781 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { |
809 | if (strcmp(data, tomoyo_dp_keyword[type])) | 782 | if (strcmp(data, tomoyo_path2_keyword[type])) |
810 | continue; | 783 | continue; |
811 | return tomoyo_update_double_path_acl(type, filename, filename2, | 784 | return tomoyo_update_path2_acl(type, filename, filename2, |
812 | domain, is_delete); | 785 | domain, is_delete); |
813 | } | 786 | } |
814 | out: | 787 | out: |
815 | return -EINVAL; | 788 | return -EINVAL; |
816 | } | 789 | } |
817 | 790 | ||
818 | /** | 791 | /** |
819 | * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. | 792 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
820 | * | 793 | * |
821 | * @type: Type of operation. | 794 | * @type: Type of operation. |
822 | * @filename: Filename. | 795 | * @filename: Filename. |
@@ -824,85 +797,82 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
824 | * @is_delete: True if it is a delete request. | 797 | * @is_delete: True if it is a delete request. |
825 | * | 798 | * |
826 | * Returns 0 on success, negative value otherwise. | 799 | * Returns 0 on success, negative value otherwise. |
800 | * | ||
801 | * Caller holds tomoyo_read_lock(). | ||
827 | */ | 802 | */ |
828 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | 803 | static int tomoyo_update_path_acl(const u8 type, const char *filename, |
829 | struct tomoyo_domain_info * | 804 | struct tomoyo_domain_info *const domain, |
830 | const domain, const bool is_delete) | 805 | const bool is_delete) |
831 | { | 806 | { |
832 | static const u16 rw_mask = | 807 | static const u32 rw_mask = |
833 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); | 808 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); |
834 | const struct tomoyo_path_info *saved_filename; | 809 | const struct tomoyo_path_info *saved_filename; |
835 | struct tomoyo_acl_info *ptr; | 810 | struct tomoyo_acl_info *ptr; |
836 | struct tomoyo_single_path_acl_record *acl; | 811 | struct tomoyo_path_acl *entry = NULL; |
837 | int error = -ENOMEM; | 812 | int error = is_delete ? -ENOENT : -ENOMEM; |
838 | const u16 perm = 1 << type; | 813 | const u32 perm = 1 << type; |
839 | 814 | ||
840 | if (!domain) | 815 | if (!domain) |
841 | return -EINVAL; | 816 | return -EINVAL; |
842 | if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) | 817 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) |
843 | return -EINVAL; | 818 | return -EINVAL; |
844 | saved_filename = tomoyo_save_name(filename); | 819 | saved_filename = tomoyo_get_name(filename); |
845 | if (!saved_filename) | 820 | if (!saved_filename) |
846 | return -ENOMEM; | 821 | return -ENOMEM; |
847 | down_write(&tomoyo_domain_acl_info_list_lock); | 822 | if (!is_delete) |
848 | if (is_delete) | 823 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
849 | goto delete; | 824 | mutex_lock(&tomoyo_policy_lock); |
850 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 825 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
851 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | 826 | struct tomoyo_path_acl *acl = |
827 | container_of(ptr, struct tomoyo_path_acl, head); | ||
828 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) | ||
852 | continue; | 829 | continue; |
853 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
854 | head); | ||
855 | if (acl->filename != saved_filename) | 830 | if (acl->filename != saved_filename) |
856 | continue; | 831 | continue; |
857 | /* Special case. Clear all bits if marked as deleted. */ | 832 | if (is_delete) { |
858 | if (ptr->type & TOMOYO_ACL_DELETED) | 833 | if (perm <= 0xFFFF) |
859 | acl->perm = 0; | 834 | acl->perm &= ~perm; |
860 | acl->perm |= perm; | 835 | else |
861 | if ((acl->perm & rw_mask) == rw_mask) | 836 | acl->perm_high &= ~(perm >> 16); |
862 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 837 | if ((acl->perm & rw_mask) != rw_mask) |
863 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 838 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); |
864 | acl->perm |= rw_mask; | 839 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
865 | ptr->type &= ~TOMOYO_ACL_DELETED; | 840 | acl->perm &= ~rw_mask; |
841 | } else { | ||
842 | if (perm <= 0xFFFF) | ||
843 | acl->perm |= perm; | ||
844 | else | ||
845 | acl->perm_high |= (perm >> 16); | ||
846 | if ((acl->perm & rw_mask) == rw_mask) | ||
847 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; | ||
848 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
849 | acl->perm |= rw_mask; | ||
850 | } | ||
866 | error = 0; | 851 | error = 0; |
867 | goto out; | 852 | break; |
868 | } | 853 | } |
869 | /* Not found. Append it to the tail. */ | 854 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
870 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); | 855 | entry->head.type = TOMOYO_TYPE_PATH_ACL; |
871 | if (!acl) | 856 | if (perm <= 0xFFFF) |
872 | goto out; | 857 | entry->perm = perm; |
873 | acl->perm = perm; | 858 | else |
874 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 859 | entry->perm_high = (perm >> 16); |
875 | acl->perm |= rw_mask; | 860 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) |
876 | acl->filename = saved_filename; | 861 | entry->perm |= rw_mask; |
877 | list_add_tail(&acl->head.list, &domain->acl_info_list); | 862 | entry->filename = saved_filename; |
878 | error = 0; | 863 | saved_filename = NULL; |
879 | goto out; | 864 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); |
880 | delete: | 865 | entry = NULL; |
881 | error = -ENOENT; | ||
882 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
883 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
884 | continue; | ||
885 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
886 | head); | ||
887 | if (acl->filename != saved_filename) | ||
888 | continue; | ||
889 | acl->perm &= ~perm; | ||
890 | if ((acl->perm & rw_mask) != rw_mask) | ||
891 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); | ||
892 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | ||
893 | acl->perm &= ~rw_mask; | ||
894 | if (!acl->perm) | ||
895 | ptr->type |= TOMOYO_ACL_DELETED; | ||
896 | error = 0; | 866 | error = 0; |
897 | break; | ||
898 | } | 867 | } |
899 | out: | 868 | mutex_unlock(&tomoyo_policy_lock); |
900 | up_write(&tomoyo_domain_acl_info_list_lock); | 869 | kfree(entry); |
870 | tomoyo_put_name(saved_filename); | ||
901 | return error; | 871 | return error; |
902 | } | 872 | } |
903 | 873 | ||
904 | /** | 874 | /** |
905 | * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. | 875 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
906 | * | 876 | * |
907 | * @type: Type of operation. | 877 | * @type: Type of operation. |
908 | * @filename1: First filename. | 878 | * @filename1: First filename. |
@@ -911,98 +881,88 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
911 | * @is_delete: True if it is a delete request. | 881 | * @is_delete: True if it is a delete request. |
912 | * | 882 | * |
913 | * Returns 0 on success, negative value otherwise. | 883 | * Returns 0 on success, negative value otherwise. |
884 | * | ||
885 | * Caller holds tomoyo_read_lock(). | ||
914 | */ | 886 | */ |
915 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 887 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
916 | const char *filename2, | 888 | const char *filename2, |
917 | struct tomoyo_domain_info * | 889 | struct tomoyo_domain_info *const domain, |
918 | const domain, const bool is_delete) | 890 | const bool is_delete) |
919 | { | 891 | { |
920 | const struct tomoyo_path_info *saved_filename1; | 892 | const struct tomoyo_path_info *saved_filename1; |
921 | const struct tomoyo_path_info *saved_filename2; | 893 | const struct tomoyo_path_info *saved_filename2; |
922 | struct tomoyo_acl_info *ptr; | 894 | struct tomoyo_acl_info *ptr; |
923 | struct tomoyo_double_path_acl_record *acl; | 895 | struct tomoyo_path2_acl *entry = NULL; |
924 | int error = -ENOMEM; | 896 | int error = is_delete ? -ENOENT : -ENOMEM; |
925 | const u8 perm = 1 << type; | 897 | const u8 perm = 1 << type; |
926 | 898 | ||
927 | if (!domain) | 899 | if (!domain) |
928 | return -EINVAL; | 900 | return -EINVAL; |
929 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || | 901 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || |
930 | !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) | 902 | !tomoyo_is_correct_path(filename2, 0, 0, 0)) |
931 | return -EINVAL; | 903 | return -EINVAL; |
932 | saved_filename1 = tomoyo_save_name(filename1); | 904 | saved_filename1 = tomoyo_get_name(filename1); |
933 | saved_filename2 = tomoyo_save_name(filename2); | 905 | saved_filename2 = tomoyo_get_name(filename2); |
934 | if (!saved_filename1 || !saved_filename2) | 906 | if (!saved_filename1 || !saved_filename2) |
935 | return -ENOMEM; | ||
936 | down_write(&tomoyo_domain_acl_info_list_lock); | ||
937 | if (is_delete) | ||
938 | goto delete; | ||
939 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
940 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
941 | continue; | ||
942 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
943 | head); | ||
944 | if (acl->filename1 != saved_filename1 || | ||
945 | acl->filename2 != saved_filename2) | ||
946 | continue; | ||
947 | /* Special case. Clear all bits if marked as deleted. */ | ||
948 | if (ptr->type & TOMOYO_ACL_DELETED) | ||
949 | acl->perm = 0; | ||
950 | acl->perm |= perm; | ||
951 | ptr->type &= ~TOMOYO_ACL_DELETED; | ||
952 | error = 0; | ||
953 | goto out; | 907 | goto out; |
954 | } | 908 | if (!is_delete) |
955 | /* Not found. Append it to the tail. */ | 909 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
956 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); | 910 | mutex_lock(&tomoyo_policy_lock); |
957 | if (!acl) | 911 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
958 | goto out; | 912 | struct tomoyo_path2_acl *acl = |
959 | acl->perm = perm; | 913 | container_of(ptr, struct tomoyo_path2_acl, head); |
960 | acl->filename1 = saved_filename1; | 914 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) |
961 | acl->filename2 = saved_filename2; | ||
962 | list_add_tail(&acl->head.list, &domain->acl_info_list); | ||
963 | error = 0; | ||
964 | goto out; | ||
965 | delete: | ||
966 | error = -ENOENT; | ||
967 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
968 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
969 | continue; | 915 | continue; |
970 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
971 | head); | ||
972 | if (acl->filename1 != saved_filename1 || | 916 | if (acl->filename1 != saved_filename1 || |
973 | acl->filename2 != saved_filename2) | 917 | acl->filename2 != saved_filename2) |
974 | continue; | 918 | continue; |
975 | acl->perm &= ~perm; | 919 | if (is_delete) |
976 | if (!acl->perm) | 920 | acl->perm &= ~perm; |
977 | ptr->type |= TOMOYO_ACL_DELETED; | 921 | else |
922 | acl->perm |= perm; | ||
978 | error = 0; | 923 | error = 0; |
979 | break; | 924 | break; |
980 | } | 925 | } |
926 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | ||
927 | entry->head.type = TOMOYO_TYPE_PATH2_ACL; | ||
928 | entry->perm = perm; | ||
929 | entry->filename1 = saved_filename1; | ||
930 | saved_filename1 = NULL; | ||
931 | entry->filename2 = saved_filename2; | ||
932 | saved_filename2 = NULL; | ||
933 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); | ||
934 | entry = NULL; | ||
935 | error = 0; | ||
936 | } | ||
937 | mutex_unlock(&tomoyo_policy_lock); | ||
981 | out: | 938 | out: |
982 | up_write(&tomoyo_domain_acl_info_list_lock); | 939 | tomoyo_put_name(saved_filename1); |
940 | tomoyo_put_name(saved_filename2); | ||
941 | kfree(entry); | ||
983 | return error; | 942 | return error; |
984 | } | 943 | } |
985 | 944 | ||
986 | /** | 945 | /** |
987 | * tomoyo_check_single_path_acl - Check permission for single path operation. | 946 | * tomoyo_path_acl - Check permission for single path operation. |
988 | * | 947 | * |
989 | * @domain: Pointer to "struct tomoyo_domain_info". | 948 | * @domain: Pointer to "struct tomoyo_domain_info". |
990 | * @type: Type of operation. | 949 | * @type: Type of operation. |
991 | * @filename: Filename to check. | 950 | * @filename: Filename to check. |
992 | * | 951 | * |
993 | * Returns 0 on success, negative value otherwise. | 952 | * Returns 0 on success, negative value otherwise. |
953 | * | ||
954 | * Caller holds tomoyo_read_lock(). | ||
994 | */ | 955 | */ |
995 | static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | 956 | static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, |
996 | const u8 type, | 957 | const struct tomoyo_path_info *filename) |
997 | const struct tomoyo_path_info *filename) | ||
998 | { | 958 | { |
999 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 959 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
1000 | return 0; | 960 | return 0; |
1001 | return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); | 961 | return tomoyo_path_acl2(domain, filename, 1 << type, 1); |
1002 | } | 962 | } |
1003 | 963 | ||
1004 | /** | 964 | /** |
1005 | * tomoyo_check_double_path_acl - Check permission for double path operation. | 965 | * tomoyo_path2_acl - Check permission for double path operation. |
1006 | * | 966 | * |
1007 | * @domain: Pointer to "struct tomoyo_domain_info". | 967 | * @domain: Pointer to "struct tomoyo_domain_info". |
1008 | * @type: Type of operation. | 968 | * @type: Type of operation. |
@@ -1010,13 +970,13 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | |||
1010 | * @filename2: Second filename to check. | 970 | * @filename2: Second filename to check. |
1011 | * | 971 | * |
1012 | * Returns 0 on success, -EPERM otherwise. | 972 | * Returns 0 on success, -EPERM otherwise. |
973 | * | ||
974 | * Caller holds tomoyo_read_lock(). | ||
1013 | */ | 975 | */ |
1014 | static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | 976 | static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, |
1015 | const u8 type, | 977 | const u8 type, |
1016 | const struct tomoyo_path_info * | 978 | const struct tomoyo_path_info *filename1, |
1017 | filename1, | 979 | const struct tomoyo_path_info *filename2) |
1018 | const struct tomoyo_path_info * | ||
1019 | filename2) | ||
1020 | { | 980 | { |
1021 | struct tomoyo_acl_info *ptr; | 981 | struct tomoyo_acl_info *ptr; |
1022 | const u8 perm = 1 << type; | 982 | const u8 perm = 1 << type; |
@@ -1024,13 +984,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1024 | 984 | ||
1025 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 985 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
1026 | return 0; | 986 | return 0; |
1027 | down_read(&tomoyo_domain_acl_info_list_lock); | 987 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
1028 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 988 | struct tomoyo_path2_acl *acl; |
1029 | struct tomoyo_double_path_acl_record *acl; | 989 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) |
1030 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
1031 | continue; | 990 | continue; |
1032 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | 991 | acl = container_of(ptr, struct tomoyo_path2_acl, head); |
1033 | head); | ||
1034 | if (!(acl->perm & perm)) | 992 | if (!(acl->perm & perm)) |
1035 | continue; | 993 | continue; |
1036 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) | 994 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) |
@@ -1040,12 +998,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1040 | error = 0; | 998 | error = 0; |
1041 | break; | 999 | break; |
1042 | } | 1000 | } |
1043 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
1044 | return error; | 1001 | return error; |
1045 | } | 1002 | } |
1046 | 1003 | ||
1047 | /** | 1004 | /** |
1048 | * tomoyo_check_single_path_permission2 - Check permission for single path operation. | 1005 | * tomoyo_path_permission2 - Check permission for single path operation. |
1049 | * | 1006 | * |
1050 | * @domain: Pointer to "struct tomoyo_domain_info". | 1007 | * @domain: Pointer to "struct tomoyo_domain_info". |
1051 | * @operation: Type of operation. | 1008 | * @operation: Type of operation. |
@@ -1053,11 +1010,13 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1053 | * @mode: Access control mode. | 1010 | * @mode: Access control mode. |
1054 | * | 1011 | * |
1055 | * Returns 0 on success, negative value otherwise. | 1012 | * Returns 0 on success, negative value otherwise. |
1013 | * | ||
1014 | * Caller holds tomoyo_read_lock(). | ||
1056 | */ | 1015 | */ |
1057 | static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | 1016 | static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, |
1058 | const domain, u8 operation, | 1017 | u8 operation, |
1059 | const struct tomoyo_path_info * | 1018 | const struct tomoyo_path_info *filename, |
1060 | filename, const u8 mode) | 1019 | const u8 mode) |
1061 | { | 1020 | { |
1062 | const char *msg; | 1021 | const char *msg; |
1063 | int error; | 1022 | int error; |
@@ -1066,8 +1025,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1066 | if (!mode) | 1025 | if (!mode) |
1067 | return 0; | 1026 | return 0; |
1068 | next: | 1027 | next: |
1069 | error = tomoyo_check_single_path_acl(domain, operation, filename); | 1028 | error = tomoyo_path_acl(domain, operation, filename); |
1070 | msg = tomoyo_sp2keyword(operation); | 1029 | msg = tomoyo_path2keyword(operation); |
1071 | if (!error) | 1030 | if (!error) |
1072 | goto ok; | 1031 | goto ok; |
1073 | if (tomoyo_verbose_mode(domain)) | 1032 | if (tomoyo_verbose_mode(domain)) |
@@ -1076,7 +1035,7 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1076 | tomoyo_get_last_name(domain)); | 1035 | tomoyo_get_last_name(domain)); |
1077 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1036 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1078 | const char *name = tomoyo_get_file_pattern(filename)->name; | 1037 | const char *name = tomoyo_get_file_pattern(filename)->name; |
1079 | tomoyo_update_single_path_acl(operation, name, domain, false); | 1038 | tomoyo_update_path_acl(operation, name, domain, false); |
1080 | } | 1039 | } |
1081 | if (!is_enforce) | 1040 | if (!is_enforce) |
1082 | error = 0; | 1041 | error = 0; |
@@ -1086,9 +1045,9 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1086 | * we need to check "allow_rewrite" permission if the filename is | 1045 | * we need to check "allow_rewrite" permission if the filename is |
1087 | * specified by "deny_rewrite" keyword. | 1046 | * specified by "deny_rewrite" keyword. |
1088 | */ | 1047 | */ |
1089 | if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && | 1048 | if (!error && operation == TOMOYO_TYPE_TRUNCATE && |
1090 | tomoyo_is_no_rewrite_file(filename)) { | 1049 | tomoyo_is_no_rewrite_file(filename)) { |
1091 | operation = TOMOYO_TYPE_REWRITE_ACL; | 1050 | operation = TOMOYO_TYPE_REWRITE; |
1092 | goto next; | 1051 | goto next; |
1093 | } | 1052 | } |
1094 | return error; | 1053 | return error; |
@@ -1101,6 +1060,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1101 | * @filename: Check permission for "execute". | 1060 | * @filename: Check permission for "execute". |
1102 | * | 1061 | * |
1103 | * Returns 0 on success, negativevalue otherwise. | 1062 | * Returns 0 on success, negativevalue otherwise. |
1063 | * | ||
1064 | * Caller holds tomoyo_read_lock(). | ||
1104 | */ | 1065 | */ |
1105 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 1066 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
1106 | const struct tomoyo_path_info *filename) | 1067 | const struct tomoyo_path_info *filename) |
@@ -1129,6 +1090,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1129 | struct tomoyo_path_info *buf; | 1090 | struct tomoyo_path_info *buf; |
1130 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1091 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1131 | const bool is_enforce = (mode == 3); | 1092 | const bool is_enforce = (mode == 3); |
1093 | int idx; | ||
1132 | 1094 | ||
1133 | if (!mode || !path->mnt) | 1095 | if (!mode || !path->mnt) |
1134 | return 0; | 1096 | return 0; |
@@ -1140,6 +1102,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1140 | * don't call me. | 1102 | * don't call me. |
1141 | */ | 1103 | */ |
1142 | return 0; | 1104 | return 0; |
1105 | idx = tomoyo_read_lock(); | ||
1143 | buf = tomoyo_get_path(path); | 1106 | buf = tomoyo_get_path(path); |
1144 | if (!buf) | 1107 | if (!buf) |
1145 | goto out; | 1108 | goto out; |
@@ -1152,49 +1115,50 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1152 | if ((acc_mode & MAY_WRITE) && | 1115 | if ((acc_mode & MAY_WRITE) && |
1153 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && | 1116 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && |
1154 | (tomoyo_is_no_rewrite_file(buf))) { | 1117 | (tomoyo_is_no_rewrite_file(buf))) { |
1155 | error = tomoyo_check_single_path_permission2(domain, | 1118 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, |
1156 | TOMOYO_TYPE_REWRITE_ACL, | 1119 | buf, mode); |
1157 | buf, mode); | ||
1158 | } | 1120 | } |
1159 | if (!error) | 1121 | if (!error) |
1160 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", | 1122 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", |
1161 | mode); | 1123 | mode); |
1162 | if (!error && (flag & O_TRUNC)) | 1124 | if (!error && (flag & O_TRUNC)) |
1163 | error = tomoyo_check_single_path_permission2(domain, | 1125 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, |
1164 | TOMOYO_TYPE_TRUNCATE_ACL, | 1126 | buf, mode); |
1165 | buf, mode); | ||
1166 | out: | 1127 | out: |
1167 | tomoyo_free(buf); | 1128 | kfree(buf); |
1129 | tomoyo_read_unlock(idx); | ||
1168 | if (!is_enforce) | 1130 | if (!is_enforce) |
1169 | error = 0; | 1131 | error = 0; |
1170 | return error; | 1132 | return error; |
1171 | } | 1133 | } |
1172 | 1134 | ||
1173 | /** | 1135 | /** |
1174 | * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". | 1136 | * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". |
1175 | * | 1137 | * |
1176 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1177 | * @operation: Type of operation. | 1138 | * @operation: Type of operation. |
1178 | * @path: Pointer to "struct path". | 1139 | * @path: Pointer to "struct path". |
1179 | * | 1140 | * |
1180 | * Returns 0 on success, negative value otherwise. | 1141 | * Returns 0 on success, negative value otherwise. |
1181 | */ | 1142 | */ |
1182 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | 1143 | int tomoyo_path_perm(const u8 operation, struct path *path) |
1183 | const u8 operation, struct path *path) | ||
1184 | { | 1144 | { |
1185 | int error = -ENOMEM; | 1145 | int error = -ENOMEM; |
1186 | struct tomoyo_path_info *buf; | 1146 | struct tomoyo_path_info *buf; |
1147 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1187 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1148 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1188 | const bool is_enforce = (mode == 3); | 1149 | const bool is_enforce = (mode == 3); |
1150 | int idx; | ||
1189 | 1151 | ||
1190 | if (!mode || !path->mnt) | 1152 | if (!mode || !path->mnt) |
1191 | return 0; | 1153 | return 0; |
1154 | idx = tomoyo_read_lock(); | ||
1192 | buf = tomoyo_get_path(path); | 1155 | buf = tomoyo_get_path(path); |
1193 | if (!buf) | 1156 | if (!buf) |
1194 | goto out; | 1157 | goto out; |
1195 | switch (operation) { | 1158 | switch (operation) { |
1196 | case TOMOYO_TYPE_MKDIR_ACL: | 1159 | case TOMOYO_TYPE_MKDIR: |
1197 | case TOMOYO_TYPE_RMDIR_ACL: | 1160 | case TOMOYO_TYPE_RMDIR: |
1161 | case TOMOYO_TYPE_CHROOT: | ||
1198 | if (!buf->is_dir) { | 1162 | if (!buf->is_dir) { |
1199 | /* | 1163 | /* |
1200 | * tomoyo_get_path() reserves space for appending "/." | 1164 | * tomoyo_get_path() reserves space for appending "/." |
@@ -1203,10 +1167,10 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | |||
1203 | tomoyo_fill_path_info(buf); | 1167 | tomoyo_fill_path_info(buf); |
1204 | } | 1168 | } |
1205 | } | 1169 | } |
1206 | error = tomoyo_check_single_path_permission2(domain, operation, buf, | 1170 | error = tomoyo_path_permission2(domain, operation, buf, mode); |
1207 | mode); | ||
1208 | out: | 1171 | out: |
1209 | tomoyo_free(buf); | 1172 | kfree(buf); |
1173 | tomoyo_read_unlock(idx); | ||
1210 | if (!is_enforce) | 1174 | if (!is_enforce) |
1211 | error = 0; | 1175 | error = 0; |
1212 | return error; | 1176 | return error; |
@@ -1215,21 +1179,23 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | |||
1215 | /** | 1179 | /** |
1216 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". | 1180 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". |
1217 | * | 1181 | * |
1218 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1219 | * @filp: Pointer to "struct file". | 1182 | * @filp: Pointer to "struct file". |
1220 | * | 1183 | * |
1221 | * Returns 0 on success, negative value otherwise. | 1184 | * Returns 0 on success, negative value otherwise. |
1222 | */ | 1185 | */ |
1223 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 1186 | int tomoyo_check_rewrite_permission(struct file *filp) |
1224 | struct file *filp) | ||
1225 | { | 1187 | { |
1226 | int error = -ENOMEM; | 1188 | int error = -ENOMEM; |
1189 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1227 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1190 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1228 | const bool is_enforce = (mode == 3); | 1191 | const bool is_enforce = (mode == 3); |
1229 | struct tomoyo_path_info *buf; | 1192 | struct tomoyo_path_info *buf; |
1193 | int idx; | ||
1230 | 1194 | ||
1231 | if (!mode || !filp->f_path.mnt) | 1195 | if (!mode || !filp->f_path.mnt) |
1232 | return 0; | 1196 | return 0; |
1197 | |||
1198 | idx = tomoyo_read_lock(); | ||
1233 | buf = tomoyo_get_path(&filp->f_path); | 1199 | buf = tomoyo_get_path(&filp->f_path); |
1234 | if (!buf) | 1200 | if (!buf) |
1235 | goto out; | 1201 | goto out; |
@@ -1237,38 +1203,38 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | |||
1237 | error = 0; | 1203 | error = 0; |
1238 | goto out; | 1204 | goto out; |
1239 | } | 1205 | } |
1240 | error = tomoyo_check_single_path_permission2(domain, | 1206 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); |
1241 | TOMOYO_TYPE_REWRITE_ACL, | ||
1242 | buf, mode); | ||
1243 | out: | 1207 | out: |
1244 | tomoyo_free(buf); | 1208 | kfree(buf); |
1209 | tomoyo_read_unlock(idx); | ||
1245 | if (!is_enforce) | 1210 | if (!is_enforce) |
1246 | error = 0; | 1211 | error = 0; |
1247 | return error; | 1212 | return error; |
1248 | } | 1213 | } |
1249 | 1214 | ||
1250 | /** | 1215 | /** |
1251 | * tomoyo_check_2path_perm - Check permission for "rename" and "link". | 1216 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". |
1252 | * | 1217 | * |
1253 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1254 | * @operation: Type of operation. | 1218 | * @operation: Type of operation. |
1255 | * @path1: Pointer to "struct path". | 1219 | * @path1: Pointer to "struct path". |
1256 | * @path2: Pointer to "struct path". | 1220 | * @path2: Pointer to "struct path". |
1257 | * | 1221 | * |
1258 | * Returns 0 on success, negative value otherwise. | 1222 | * Returns 0 on success, negative value otherwise. |
1259 | */ | 1223 | */ |
1260 | int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | 1224 | int tomoyo_path2_perm(const u8 operation, struct path *path1, |
1261 | const u8 operation, struct path *path1, | 1225 | struct path *path2) |
1262 | struct path *path2) | ||
1263 | { | 1226 | { |
1264 | int error = -ENOMEM; | 1227 | int error = -ENOMEM; |
1265 | struct tomoyo_path_info *buf1, *buf2; | 1228 | struct tomoyo_path_info *buf1, *buf2; |
1229 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1266 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1230 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1267 | const bool is_enforce = (mode == 3); | 1231 | const bool is_enforce = (mode == 3); |
1268 | const char *msg; | 1232 | const char *msg; |
1233 | int idx; | ||
1269 | 1234 | ||
1270 | if (!mode || !path1->mnt || !path2->mnt) | 1235 | if (!mode || !path1->mnt || !path2->mnt) |
1271 | return 0; | 1236 | return 0; |
1237 | idx = tomoyo_read_lock(); | ||
1272 | buf1 = tomoyo_get_path(path1); | 1238 | buf1 = tomoyo_get_path(path1); |
1273 | buf2 = tomoyo_get_path(path2); | 1239 | buf2 = tomoyo_get_path(path2); |
1274 | if (!buf1 || !buf2) | 1240 | if (!buf1 || !buf2) |
@@ -1289,8 +1255,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | |||
1289 | } | 1255 | } |
1290 | } | 1256 | } |
1291 | } | 1257 | } |
1292 | error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); | 1258 | error = tomoyo_path2_acl(domain, operation, buf1, buf2); |
1293 | msg = tomoyo_dp2keyword(operation); | 1259 | msg = tomoyo_path22keyword(operation); |
1294 | if (!error) | 1260 | if (!error) |
1295 | goto out; | 1261 | goto out; |
1296 | if (tomoyo_verbose_mode(domain)) | 1262 | if (tomoyo_verbose_mode(domain)) |
@@ -1301,12 +1267,13 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | |||
1301 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1267 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1302 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; | 1268 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; |
1303 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; | 1269 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; |
1304 | tomoyo_update_double_path_acl(operation, name1, name2, domain, | 1270 | tomoyo_update_path2_acl(operation, name1, name2, domain, |
1305 | false); | 1271 | false); |
1306 | } | 1272 | } |
1307 | out: | 1273 | out: |
1308 | tomoyo_free(buf1); | 1274 | kfree(buf1); |
1309 | tomoyo_free(buf2); | 1275 | kfree(buf2); |
1276 | tomoyo_read_unlock(idx); | ||
1310 | if (!is_enforce) | 1277 | if (!is_enforce) |
1311 | error = 0; | 1278 | error = 0; |
1312 | return error; | 1279 | return error; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c new file mode 100644 index 000000000000..9645525ccdd4 --- /dev/null +++ b/security/tomoyo/gc.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * security/tomoyo/gc.c | ||
3 | * | ||
4 | * Implementation of the Domain-Based Mandatory Access Control. | ||
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include "common.h" | ||
11 | #include <linux/kthread.h> | ||
12 | |||
13 | enum tomoyo_gc_id { | ||
14 | TOMOYO_ID_DOMAIN_INITIALIZER, | ||
15 | TOMOYO_ID_DOMAIN_KEEPER, | ||
16 | TOMOYO_ID_ALIAS, | ||
17 | TOMOYO_ID_GLOBALLY_READABLE, | ||
18 | TOMOYO_ID_PATTERN, | ||
19 | TOMOYO_ID_NO_REWRITE, | ||
20 | TOMOYO_ID_MANAGER, | ||
21 | TOMOYO_ID_NAME, | ||
22 | TOMOYO_ID_ACL, | ||
23 | TOMOYO_ID_DOMAIN | ||
24 | }; | ||
25 | |||
26 | struct tomoyo_gc_entry { | ||
27 | struct list_head list; | ||
28 | int type; | ||
29 | void *element; | ||
30 | }; | ||
31 | static LIST_HEAD(tomoyo_gc_queue); | ||
32 | static DEFINE_MUTEX(tomoyo_gc_mutex); | ||
33 | |||
34 | /* Caller holds tomoyo_policy_lock mutex. */ | ||
35 | static bool tomoyo_add_to_gc(const int type, void *element) | ||
36 | { | ||
37 | struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
38 | if (!entry) | ||
39 | return false; | ||
40 | entry->type = type; | ||
41 | entry->element = element; | ||
42 | list_add(&entry->list, &tomoyo_gc_queue); | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | static void tomoyo_del_allow_read | ||
47 | (struct tomoyo_globally_readable_file_entry *ptr) | ||
48 | { | ||
49 | tomoyo_put_name(ptr->filename); | ||
50 | } | ||
51 | |||
52 | static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) | ||
53 | { | ||
54 | tomoyo_put_name(ptr->pattern); | ||
55 | } | ||
56 | |||
57 | static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) | ||
58 | { | ||
59 | tomoyo_put_name(ptr->pattern); | ||
60 | } | ||
61 | |||
62 | static void tomoyo_del_domain_initializer | ||
63 | (struct tomoyo_domain_initializer_entry *ptr) | ||
64 | { | ||
65 | tomoyo_put_name(ptr->domainname); | ||
66 | tomoyo_put_name(ptr->program); | ||
67 | } | ||
68 | |||
69 | static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) | ||
70 | { | ||
71 | tomoyo_put_name(ptr->domainname); | ||
72 | tomoyo_put_name(ptr->program); | ||
73 | } | ||
74 | |||
75 | static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) | ||
76 | { | ||
77 | tomoyo_put_name(ptr->original_name); | ||
78 | tomoyo_put_name(ptr->aliased_name); | ||
79 | } | ||
80 | |||
81 | static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) | ||
82 | { | ||
83 | tomoyo_put_name(ptr->manager); | ||
84 | } | ||
85 | |||
86 | static void tomoyo_del_acl(struct tomoyo_acl_info *acl) | ||
87 | { | ||
88 | switch (acl->type) { | ||
89 | case TOMOYO_TYPE_PATH_ACL: | ||
90 | { | ||
91 | struct tomoyo_path_acl *entry | ||
92 | = container_of(acl, typeof(*entry), head); | ||
93 | tomoyo_put_name(entry->filename); | ||
94 | } | ||
95 | break; | ||
96 | case TOMOYO_TYPE_PATH2_ACL: | ||
97 | { | ||
98 | struct tomoyo_path2_acl *entry | ||
99 | = container_of(acl, typeof(*entry), head); | ||
100 | tomoyo_put_name(entry->filename1); | ||
101 | tomoyo_put_name(entry->filename2); | ||
102 | } | ||
103 | break; | ||
104 | default: | ||
105 | printk(KERN_WARNING "Unknown type\n"); | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) | ||
111 | { | ||
112 | struct tomoyo_acl_info *acl; | ||
113 | struct tomoyo_acl_info *tmp; | ||
114 | /* | ||
115 | * Since we don't protect whole execve() operation using SRCU, | ||
116 | * we need to recheck domain->users at this point. | ||
117 | * | ||
118 | * (1) Reader starts SRCU section upon execve(). | ||
119 | * (2) Reader traverses tomoyo_domain_list and finds this domain. | ||
120 | * (3) Writer marks this domain as deleted. | ||
121 | * (4) Garbage collector removes this domain from tomoyo_domain_list | ||
122 | * because this domain is marked as deleted and used by nobody. | ||
123 | * (5) Reader saves reference to this domain into | ||
124 | * "struct linux_binprm"->cred->security . | ||
125 | * (6) Reader finishes SRCU section, although execve() operation has | ||
126 | * not finished yet. | ||
127 | * (7) Garbage collector waits for SRCU synchronization. | ||
128 | * (8) Garbage collector kfree() this domain because this domain is | ||
129 | * used by nobody. | ||
130 | * (9) Reader finishes execve() operation and restores this domain from | ||
131 | * "struct linux_binprm"->cred->security. | ||
132 | * | ||
133 | * By updating domain->users at (5), we can solve this race problem | ||
134 | * by rechecking domain->users at (8). | ||
135 | */ | ||
136 | if (atomic_read(&domain->users)) | ||
137 | return false; | ||
138 | list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { | ||
139 | tomoyo_del_acl(acl); | ||
140 | tomoyo_memory_free(acl); | ||
141 | } | ||
142 | tomoyo_put_name(domain->domainname); | ||
143 | return true; | ||
144 | } | ||
145 | |||
146 | |||
147 | static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) | ||
148 | { | ||
149 | } | ||
150 | |||
151 | static void tomoyo_collect_entry(void) | ||
152 | { | ||
153 | mutex_lock(&tomoyo_policy_lock); | ||
154 | { | ||
155 | struct tomoyo_globally_readable_file_entry *ptr; | ||
156 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, | ||
157 | list) { | ||
158 | if (!ptr->is_deleted) | ||
159 | continue; | ||
160 | if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) | ||
161 | list_del_rcu(&ptr->list); | ||
162 | else | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | { | ||
167 | struct tomoyo_pattern_entry *ptr; | ||
168 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
169 | if (!ptr->is_deleted) | ||
170 | continue; | ||
171 | if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) | ||
172 | list_del_rcu(&ptr->list); | ||
173 | else | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | { | ||
178 | struct tomoyo_no_rewrite_entry *ptr; | ||
179 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
180 | if (!ptr->is_deleted) | ||
181 | continue; | ||
182 | if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) | ||
183 | list_del_rcu(&ptr->list); | ||
184 | else | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | { | ||
189 | struct tomoyo_domain_initializer_entry *ptr; | ||
190 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, | ||
191 | list) { | ||
192 | if (!ptr->is_deleted) | ||
193 | continue; | ||
194 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) | ||
195 | list_del_rcu(&ptr->list); | ||
196 | else | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | { | ||
201 | struct tomoyo_domain_keeper_entry *ptr; | ||
202 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | ||
203 | if (!ptr->is_deleted) | ||
204 | continue; | ||
205 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) | ||
206 | list_del_rcu(&ptr->list); | ||
207 | else | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | { | ||
212 | struct tomoyo_alias_entry *ptr; | ||
213 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | ||
214 | if (!ptr->is_deleted) | ||
215 | continue; | ||
216 | if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) | ||
217 | list_del_rcu(&ptr->list); | ||
218 | else | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | { | ||
223 | struct tomoyo_policy_manager_entry *ptr; | ||
224 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, | ||
225 | list) { | ||
226 | if (!ptr->is_deleted) | ||
227 | continue; | ||
228 | if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) | ||
229 | list_del_rcu(&ptr->list); | ||
230 | else | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | { | ||
235 | struct tomoyo_domain_info *domain; | ||
236 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | ||
237 | struct tomoyo_acl_info *acl; | ||
238 | list_for_each_entry_rcu(acl, &domain->acl_info_list, | ||
239 | list) { | ||
240 | switch (acl->type) { | ||
241 | case TOMOYO_TYPE_PATH_ACL: | ||
242 | if (container_of(acl, | ||
243 | struct tomoyo_path_acl, | ||
244 | head)->perm || | ||
245 | container_of(acl, | ||
246 | struct tomoyo_path_acl, | ||
247 | head)->perm_high) | ||
248 | continue; | ||
249 | break; | ||
250 | case TOMOYO_TYPE_PATH2_ACL: | ||
251 | if (container_of(acl, | ||
252 | struct tomoyo_path2_acl, | ||
253 | head)->perm) | ||
254 | continue; | ||
255 | break; | ||
256 | default: | ||
257 | continue; | ||
258 | } | ||
259 | if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) | ||
260 | list_del_rcu(&acl->list); | ||
261 | else | ||
262 | break; | ||
263 | } | ||
264 | if (!domain->is_deleted || atomic_read(&domain->users)) | ||
265 | continue; | ||
266 | /* | ||
267 | * Nobody is referring this domain. But somebody may | ||
268 | * refer this domain after successful execve(). | ||
269 | * We recheck domain->users after SRCU synchronization. | ||
270 | */ | ||
271 | if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) | ||
272 | list_del_rcu(&domain->list); | ||
273 | else | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | mutex_unlock(&tomoyo_policy_lock); | ||
278 | mutex_lock(&tomoyo_name_list_lock); | ||
279 | { | ||
280 | int i; | ||
281 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | ||
282 | struct tomoyo_name_entry *ptr; | ||
283 | list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], | ||
284 | list) { | ||
285 | if (atomic_read(&ptr->users)) | ||
286 | continue; | ||
287 | if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) | ||
288 | list_del_rcu(&ptr->list); | ||
289 | else { | ||
290 | i = TOMOYO_MAX_HASH; | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | mutex_unlock(&tomoyo_name_list_lock); | ||
297 | } | ||
298 | |||
299 | static void tomoyo_kfree_entry(void) | ||
300 | { | ||
301 | struct tomoyo_gc_entry *p; | ||
302 | struct tomoyo_gc_entry *tmp; | ||
303 | |||
304 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { | ||
305 | switch (p->type) { | ||
306 | case TOMOYO_ID_DOMAIN_INITIALIZER: | ||
307 | tomoyo_del_domain_initializer(p->element); | ||
308 | break; | ||
309 | case TOMOYO_ID_DOMAIN_KEEPER: | ||
310 | tomoyo_del_domain_keeper(p->element); | ||
311 | break; | ||
312 | case TOMOYO_ID_ALIAS: | ||
313 | tomoyo_del_alias(p->element); | ||
314 | break; | ||
315 | case TOMOYO_ID_GLOBALLY_READABLE: | ||
316 | tomoyo_del_allow_read(p->element); | ||
317 | break; | ||
318 | case TOMOYO_ID_PATTERN: | ||
319 | tomoyo_del_file_pattern(p->element); | ||
320 | break; | ||
321 | case TOMOYO_ID_NO_REWRITE: | ||
322 | tomoyo_del_no_rewrite(p->element); | ||
323 | break; | ||
324 | case TOMOYO_ID_MANAGER: | ||
325 | tomoyo_del_manager(p->element); | ||
326 | break; | ||
327 | case TOMOYO_ID_NAME: | ||
328 | tomoyo_del_name(p->element); | ||
329 | break; | ||
330 | case TOMOYO_ID_ACL: | ||
331 | tomoyo_del_acl(p->element); | ||
332 | break; | ||
333 | case TOMOYO_ID_DOMAIN: | ||
334 | if (!tomoyo_del_domain(p->element)) | ||
335 | continue; | ||
336 | break; | ||
337 | default: | ||
338 | printk(KERN_WARNING "Unknown type\n"); | ||
339 | break; | ||
340 | } | ||
341 | tomoyo_memory_free(p->element); | ||
342 | list_del(&p->list); | ||
343 | kfree(p); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static int tomoyo_gc_thread(void *unused) | ||
348 | { | ||
349 | daemonize("GC for TOMOYO"); | ||
350 | if (mutex_trylock(&tomoyo_gc_mutex)) { | ||
351 | int i; | ||
352 | for (i = 0; i < 10; i++) { | ||
353 | tomoyo_collect_entry(); | ||
354 | if (list_empty(&tomoyo_gc_queue)) | ||
355 | break; | ||
356 | synchronize_srcu(&tomoyo_ss); | ||
357 | tomoyo_kfree_entry(); | ||
358 | } | ||
359 | mutex_unlock(&tomoyo_gc_mutex); | ||
360 | } | ||
361 | do_exit(0); | ||
362 | } | ||
363 | |||
364 | void tomoyo_run_gc(void) | ||
365 | { | ||
366 | struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, | ||
367 | "GC for TOMOYO"); | ||
368 | if (!IS_ERR(task)) | ||
369 | wake_up_process(task); | ||
370 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 18369d497eb8..c00df45c7ede 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -14,9 +14,8 @@ | |||
14 | #include <linux/mnt_namespace.h> | 14 | #include <linux/mnt_namespace.h> |
15 | #include <linux/fs_struct.h> | 15 | #include <linux/fs_struct.h> |
16 | #include <linux/hash.h> | 16 | #include <linux/hash.h> |
17 | 17 | #include <linux/magic.h> | |
18 | #include "common.h" | 18 | #include "common.h" |
19 | #include "realpath.h" | ||
20 | 19 | ||
21 | /** | 20 | /** |
22 | * tomoyo_encode: Convert binary string to ascii string. | 21 | * tomoyo_encode: Convert binary string to ascii string. |
@@ -112,7 +111,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
112 | path_put(&ns_root); | 111 | path_put(&ns_root); |
113 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ | 112 | /* Prepend "/proc" prefix if using internal proc vfs mount. */ |
114 | if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && | 113 | if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && |
115 | (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) { | 114 | (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { |
116 | sp -= 5; | 115 | sp -= 5; |
117 | if (sp >= newname) | 116 | if (sp >= newname) |
118 | memcpy(sp, "/proc", 5); | 117 | memcpy(sp, "/proc", 5); |
@@ -149,12 +148,12 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
149 | * | 148 | * |
150 | * Returns the realpath of the given @path on success, NULL otherwise. | 149 | * Returns the realpath of the given @path on success, NULL otherwise. |
151 | * | 150 | * |
152 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() | 151 | * These functions use kzalloc(), so the caller must call kfree() |
153 | * if these functions didn't return NULL. | 152 | * if these functions didn't return NULL. |
154 | */ | 153 | */ |
155 | char *tomoyo_realpath_from_path(struct path *path) | 154 | char *tomoyo_realpath_from_path(struct path *path) |
156 | { | 155 | { |
157 | char *buf = tomoyo_alloc(sizeof(struct tomoyo_page_buffer)); | 156 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); |
158 | 157 | ||
159 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | 158 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
160 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | 159 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
@@ -163,7 +162,7 @@ char *tomoyo_realpath_from_path(struct path *path) | |||
163 | if (tomoyo_realpath_from_path2(path, buf, | 162 | if (tomoyo_realpath_from_path2(path, buf, |
164 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) | 163 | TOMOYO_MAX_PATHNAME_LEN - 1) == 0) |
165 | return buf; | 164 | return buf; |
166 | tomoyo_free(buf); | 165 | kfree(buf); |
167 | return NULL; | 166 | return NULL; |
168 | } | 167 | } |
169 | 168 | ||
@@ -206,98 +205,47 @@ char *tomoyo_realpath_nofollow(const char *pathname) | |||
206 | } | 205 | } |
207 | 206 | ||
208 | /* Memory allocated for non-string data. */ | 207 | /* Memory allocated for non-string data. */ |
209 | static unsigned int tomoyo_allocated_memory_for_elements; | 208 | static atomic_t tomoyo_policy_memory_size; |
210 | /* Quota for holding non-string data. */ | 209 | /* Quota for holding policy. */ |
211 | static unsigned int tomoyo_quota_for_elements; | 210 | static unsigned int tomoyo_quota_for_policy; |
212 | 211 | ||
213 | /** | 212 | /** |
214 | * tomoyo_alloc_element - Allocate permanent memory for structures. | 213 | * tomoyo_memory_ok - Check memory quota. |
215 | * | 214 | * |
216 | * @size: Size in bytes. | 215 | * @ptr: Pointer to allocated memory. |
217 | * | 216 | * |
218 | * Returns pointer to allocated memory on success, NULL otherwise. | 217 | * Returns true on success, false otherwise. |
219 | * | 218 | * |
220 | * Memory has to be zeroed. | 219 | * Caller holds tomoyo_policy_lock. |
221 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. | 220 | * Memory pointed by @ptr will be zeroed on success. |
222 | */ | 221 | */ |
223 | void *tomoyo_alloc_element(const unsigned int size) | 222 | bool tomoyo_memory_ok(void *ptr) |
224 | { | 223 | { |
225 | static char *buf; | 224 | int allocated_len = ptr ? ksize(ptr) : 0; |
226 | static DEFINE_MUTEX(lock); | 225 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
227 | static unsigned int buf_used_len = PATH_MAX; | 226 | if (ptr && (!tomoyo_quota_for_policy || |
228 | char *ptr = NULL; | 227 | atomic_read(&tomoyo_policy_memory_size) |
229 | /*Assumes sizeof(void *) >= sizeof(long) is true. */ | 228 | <= tomoyo_quota_for_policy)) { |
230 | const unsigned int word_aligned_size | 229 | memset(ptr, 0, allocated_len); |
231 | = roundup(size, max(sizeof(void *), sizeof(long))); | 230 | return true; |
232 | if (word_aligned_size > PATH_MAX) | ||
233 | return NULL; | ||
234 | mutex_lock(&lock); | ||
235 | if (buf_used_len + word_aligned_size > PATH_MAX) { | ||
236 | if (!tomoyo_quota_for_elements || | ||
237 | tomoyo_allocated_memory_for_elements | ||
238 | + PATH_MAX <= tomoyo_quota_for_elements) | ||
239 | ptr = kzalloc(PATH_MAX, GFP_KERNEL); | ||
240 | if (!ptr) { | ||
241 | printk(KERN_WARNING "ERROR: Out of memory " | ||
242 | "for tomoyo_alloc_element().\n"); | ||
243 | if (!tomoyo_policy_loaded) | ||
244 | panic("MAC Initialization failed.\n"); | ||
245 | } else { | ||
246 | buf = ptr; | ||
247 | tomoyo_allocated_memory_for_elements += PATH_MAX; | ||
248 | buf_used_len = word_aligned_size; | ||
249 | ptr = buf; | ||
250 | } | ||
251 | } else if (word_aligned_size) { | ||
252 | int i; | ||
253 | ptr = buf + buf_used_len; | ||
254 | buf_used_len += word_aligned_size; | ||
255 | for (i = 0; i < word_aligned_size; i++) { | ||
256 | if (!ptr[i]) | ||
257 | continue; | ||
258 | printk(KERN_ERR "WARNING: Reserved memory was tainted! " | ||
259 | "The system might go wrong.\n"); | ||
260 | ptr[i] = '\0'; | ||
261 | } | ||
262 | } | 231 | } |
263 | mutex_unlock(&lock); | 232 | printk(KERN_WARNING "ERROR: Out of memory " |
264 | return ptr; | 233 | "for tomoyo_alloc_element().\n"); |
234 | if (!tomoyo_policy_loaded) | ||
235 | panic("MAC Initialization failed.\n"); | ||
236 | return false; | ||
265 | } | 237 | } |
266 | 238 | ||
267 | /* Memory allocated for string data in bytes. */ | 239 | /** |
268 | static unsigned int tomoyo_allocated_memory_for_savename; | 240 | * tomoyo_memory_free - Free memory for elements. |
269 | /* Quota for holding string data in bytes. */ | ||
270 | static unsigned int tomoyo_quota_for_savename; | ||
271 | |||
272 | /* | ||
273 | * TOMOYO uses this hash only when appending a string into the string | ||
274 | * table. Frequency of appending strings is very low. So we don't need | ||
275 | * large (e.g. 64k) hash size. 256 will be sufficient. | ||
276 | */ | ||
277 | #define TOMOYO_HASH_BITS 8 | ||
278 | #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) | ||
279 | |||
280 | /* | ||
281 | * tomoyo_name_entry is a structure which is used for linking | ||
282 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
283 | * | 241 | * |
284 | * Since tomoyo_name_list manages a list of strings which are shared by | 242 | * @ptr: Pointer to allocated memory. |
285 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
286 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
287 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
288 | * when TOMOYO starts supporting garbage collector. | ||
289 | */ | 243 | */ |
290 | struct tomoyo_name_entry { | 244 | void tomoyo_memory_free(void *ptr) |
291 | struct list_head list; | 245 | { |
292 | struct tomoyo_path_info entry; | 246 | atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); |
293 | }; | 247 | kfree(ptr); |
294 | 248 | } | |
295 | /* Structure for available memory region. */ | ||
296 | struct tomoyo_free_memory_block_list { | ||
297 | struct list_head list; | ||
298 | char *ptr; /* Pointer to a free area. */ | ||
299 | int len; /* Length of the area. */ | ||
300 | }; | ||
301 | 249 | ||
302 | /* | 250 | /* |
303 | * tomoyo_name_list is used for holding string data used by TOMOYO. | 251 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
@@ -305,87 +253,58 @@ struct tomoyo_free_memory_block_list { | |||
305 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of | 253 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
306 | * "const struct tomoyo_path_info *". | 254 | * "const struct tomoyo_path_info *". |
307 | */ | 255 | */ |
308 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 256 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
257 | /* Lock for protecting tomoyo_name_list . */ | ||
258 | DEFINE_MUTEX(tomoyo_name_list_lock); | ||
309 | 259 | ||
310 | /** | 260 | /** |
311 | * tomoyo_save_name - Allocate permanent memory for string data. | 261 | * tomoyo_get_name - Allocate permanent memory for string data. |
312 | * | 262 | * |
313 | * @name: The string to store into the permernent memory. | 263 | * @name: The string to store into the permernent memory. |
314 | * | 264 | * |
315 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | 265 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. |
316 | * | ||
317 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
318 | */ | 266 | */ |
319 | const struct tomoyo_path_info *tomoyo_save_name(const char *name) | 267 | const struct tomoyo_path_info *tomoyo_get_name(const char *name) |
320 | { | 268 | { |
321 | static LIST_HEAD(fmb_list); | ||
322 | static DEFINE_MUTEX(lock); | ||
323 | struct tomoyo_name_entry *ptr; | 269 | struct tomoyo_name_entry *ptr; |
324 | unsigned int hash; | 270 | unsigned int hash; |
325 | /* fmb contains available size in bytes. | ||
326 | fmb is removed from the fmb_list when fmb->len becomes 0. */ | ||
327 | struct tomoyo_free_memory_block_list *fmb; | ||
328 | int len; | 271 | int len; |
329 | char *cp; | 272 | int allocated_len; |
330 | struct list_head *head; | 273 | struct list_head *head; |
331 | 274 | ||
332 | if (!name) | 275 | if (!name) |
333 | return NULL; | 276 | return NULL; |
334 | len = strlen(name) + 1; | 277 | len = strlen(name) + 1; |
335 | if (len > TOMOYO_MAX_PATHNAME_LEN) { | ||
336 | printk(KERN_WARNING "ERROR: Name too long " | ||
337 | "for tomoyo_save_name().\n"); | ||
338 | return NULL; | ||
339 | } | ||
340 | hash = full_name_hash((const unsigned char *) name, len - 1); | 278 | hash = full_name_hash((const unsigned char *) name, len - 1); |
341 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 279 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
342 | 280 | mutex_lock(&tomoyo_name_list_lock); | |
343 | mutex_lock(&lock); | ||
344 | list_for_each_entry(ptr, head, list) { | 281 | list_for_each_entry(ptr, head, list) { |
345 | if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) | 282 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
346 | goto out; | 283 | continue; |
347 | } | 284 | atomic_inc(&ptr->users); |
348 | list_for_each_entry(fmb, &fmb_list, list) { | 285 | goto out; |
349 | if (len <= fmb->len) | ||
350 | goto ready; | ||
351 | } | 286 | } |
352 | if (!tomoyo_quota_for_savename || | 287 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); |
353 | tomoyo_allocated_memory_for_savename + PATH_MAX | 288 | allocated_len = ptr ? ksize(ptr) : 0; |
354 | <= tomoyo_quota_for_savename) | 289 | if (!ptr || (tomoyo_quota_for_policy && |
355 | cp = kzalloc(PATH_MAX, GFP_KERNEL); | 290 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
356 | else | 291 | > tomoyo_quota_for_policy)) { |
357 | cp = NULL; | 292 | kfree(ptr); |
358 | fmb = kzalloc(sizeof(*fmb), GFP_KERNEL); | ||
359 | if (!cp || !fmb) { | ||
360 | kfree(cp); | ||
361 | kfree(fmb); | ||
362 | printk(KERN_WARNING "ERROR: Out of memory " | 293 | printk(KERN_WARNING "ERROR: Out of memory " |
363 | "for tomoyo_save_name().\n"); | 294 | "for tomoyo_get_name().\n"); |
364 | if (!tomoyo_policy_loaded) | 295 | if (!tomoyo_policy_loaded) |
365 | panic("MAC Initialization failed.\n"); | 296 | panic("MAC Initialization failed.\n"); |
366 | ptr = NULL; | 297 | ptr = NULL; |
367 | goto out; | 298 | goto out; |
368 | } | 299 | } |
369 | tomoyo_allocated_memory_for_savename += PATH_MAX; | 300 | atomic_add(allocated_len, &tomoyo_policy_memory_size); |
370 | list_add(&fmb->list, &fmb_list); | 301 | ptr->entry.name = ((char *) ptr) + sizeof(*ptr); |
371 | fmb->ptr = cp; | 302 | memmove((char *) ptr->entry.name, name, len); |
372 | fmb->len = PATH_MAX; | 303 | atomic_set(&ptr->users, 1); |
373 | ready: | ||
374 | ptr = tomoyo_alloc_element(sizeof(*ptr)); | ||
375 | if (!ptr) | ||
376 | goto out; | ||
377 | ptr->entry.name = fmb->ptr; | ||
378 | memmove(fmb->ptr, name, len); | ||
379 | tomoyo_fill_path_info(&ptr->entry); | 304 | tomoyo_fill_path_info(&ptr->entry); |
380 | fmb->ptr += len; | ||
381 | fmb->len -= len; | ||
382 | list_add_tail(&ptr->list, head); | 305 | list_add_tail(&ptr->list, head); |
383 | if (fmb->len == 0) { | ||
384 | list_del(&fmb->list); | ||
385 | kfree(fmb); | ||
386 | } | ||
387 | out: | 306 | out: |
388 | mutex_unlock(&lock); | 307 | mutex_unlock(&tomoyo_name_list_lock); |
389 | return ptr ? &ptr->entry : NULL; | 308 | return ptr ? &ptr->entry : NULL; |
390 | } | 309 | } |
391 | 310 | ||
@@ -400,45 +319,14 @@ void __init tomoyo_realpath_init(void) | |||
400 | for (i = 0; i < TOMOYO_MAX_HASH; i++) | 319 | for (i = 0; i < TOMOYO_MAX_HASH; i++) |
401 | INIT_LIST_HEAD(&tomoyo_name_list[i]); | 320 | INIT_LIST_HEAD(&tomoyo_name_list[i]); |
402 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); | 321 | INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); |
403 | tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); | 322 | tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); |
404 | list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | 323 | /* |
405 | down_read(&tomoyo_domain_list_lock); | 324 | * tomoyo_read_lock() is not needed because this function is |
325 | * called before the first "delete" request. | ||
326 | */ | ||
327 | list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); | ||
406 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) | 328 | if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) |
407 | panic("Can't register tomoyo_kernel_domain"); | 329 | panic("Can't register tomoyo_kernel_domain"); |
408 | up_read(&tomoyo_domain_list_lock); | ||
409 | } | ||
410 | |||
411 | /* Memory allocated for temporary purpose. */ | ||
412 | static atomic_t tomoyo_dynamic_memory_size; | ||
413 | |||
414 | /** | ||
415 | * tomoyo_alloc - Allocate memory for temporary purpose. | ||
416 | * | ||
417 | * @size: Size in bytes. | ||
418 | * | ||
419 | * Returns pointer to allocated memory on success, NULL otherwise. | ||
420 | */ | ||
421 | void *tomoyo_alloc(const size_t size) | ||
422 | { | ||
423 | void *p = kzalloc(size, GFP_KERNEL); | ||
424 | if (p) | ||
425 | atomic_add(ksize(p), &tomoyo_dynamic_memory_size); | ||
426 | return p; | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * tomoyo_free - Release memory allocated by tomoyo_alloc(). | ||
431 | * | ||
432 | * @p: Pointer returned by tomoyo_alloc(). May be NULL. | ||
433 | * | ||
434 | * Returns nothing. | ||
435 | */ | ||
436 | void tomoyo_free(const void *p) | ||
437 | { | ||
438 | if (p) { | ||
439 | atomic_sub(ksize(p), &tomoyo_dynamic_memory_size); | ||
440 | kfree(p); | ||
441 | } | ||
442 | } | 330 | } |
443 | 331 | ||
444 | /** | 332 | /** |
@@ -451,32 +339,19 @@ void tomoyo_free(const void *p) | |||
451 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) | 339 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) |
452 | { | 340 | { |
453 | if (!head->read_eof) { | 341 | if (!head->read_eof) { |
454 | const unsigned int shared | 342 | const unsigned int policy |
455 | = tomoyo_allocated_memory_for_savename; | 343 | = atomic_read(&tomoyo_policy_memory_size); |
456 | const unsigned int private | ||
457 | = tomoyo_allocated_memory_for_elements; | ||
458 | const unsigned int dynamic | ||
459 | = atomic_read(&tomoyo_dynamic_memory_size); | ||
460 | char buffer[64]; | 344 | char buffer[64]; |
461 | 345 | ||
462 | memset(buffer, 0, sizeof(buffer)); | 346 | memset(buffer, 0, sizeof(buffer)); |
463 | if (tomoyo_quota_for_savename) | 347 | if (tomoyo_quota_for_policy) |
464 | snprintf(buffer, sizeof(buffer) - 1, | ||
465 | " (Quota: %10u)", | ||
466 | tomoyo_quota_for_savename); | ||
467 | else | ||
468 | buffer[0] = '\0'; | ||
469 | tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); | ||
470 | if (tomoyo_quota_for_elements) | ||
471 | snprintf(buffer, sizeof(buffer) - 1, | 348 | snprintf(buffer, sizeof(buffer) - 1, |
472 | " (Quota: %10u)", | 349 | " (Quota: %10u)", |
473 | tomoyo_quota_for_elements); | 350 | tomoyo_quota_for_policy); |
474 | else | 351 | else |
475 | buffer[0] = '\0'; | 352 | buffer[0] = '\0'; |
476 | tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); | 353 | tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); |
477 | tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic); | 354 | tomoyo_io_printf(head, "Total: %10u\n", policy); |
478 | tomoyo_io_printf(head, "Total: %10u\n", | ||
479 | shared + private + dynamic); | ||
480 | head->read_eof = true; | 355 | head->read_eof = true; |
481 | } | 356 | } |
482 | return 0; | 357 | return 0; |
@@ -494,9 +369,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) | |||
494 | char *data = head->write_buf; | 369 | char *data = head->write_buf; |
495 | unsigned int size; | 370 | unsigned int size; |
496 | 371 | ||
497 | if (sscanf(data, "Shared: %u", &size) == 1) | 372 | if (sscanf(data, "Policy: %u", &size) == 1) |
498 | tomoyo_quota_for_savename = size; | 373 | tomoyo_quota_for_policy = size; |
499 | else if (sscanf(data, "Private: %u", &size) == 1) | ||
500 | tomoyo_quota_for_elements = size; | ||
501 | return 0; | 374 | return 0; |
502 | } | 375 | } |
diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h deleted file mode 100644 index 78217a37960b..000000000000 --- a/security/tomoyo/realpath.h +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | /* | ||
2 | * security/tomoyo/realpath.h | ||
3 | * | ||
4 | * Get the canonicalized absolute pathnames. The basis for TOMOYO. | ||
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _SECURITY_TOMOYO_REALPATH_H | ||
13 | #define _SECURITY_TOMOYO_REALPATH_H | ||
14 | |||
15 | struct path; | ||
16 | struct tomoyo_path_info; | ||
17 | struct tomoyo_io_buffer; | ||
18 | |||
19 | /* Convert binary string to ascii string. */ | ||
20 | int tomoyo_encode(char *buffer, int buflen, const char *str); | ||
21 | |||
22 | /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */ | ||
23 | int tomoyo_realpath_from_path2(struct path *path, char *newname, | ||
24 | int newname_len); | ||
25 | |||
26 | /* | ||
27 | * Returns realpath(3) of the given pathname but ignores chroot'ed root. | ||
28 | * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() | ||
29 | * if these functions didn't return NULL. | ||
30 | */ | ||
31 | char *tomoyo_realpath(const char *pathname); | ||
32 | /* | ||
33 | * Same with tomoyo_realpath() except that it doesn't follow the final symlink. | ||
34 | */ | ||
35 | char *tomoyo_realpath_nofollow(const char *pathname); | ||
36 | /* Same with tomoyo_realpath() except that the pathname is already solved. */ | ||
37 | char *tomoyo_realpath_from_path(struct path *path); | ||
38 | |||
39 | /* | ||
40 | * Allocate memory for ACL entry. | ||
41 | * The RAM is chunked, so NEVER try to kfree() the returned pointer. | ||
42 | */ | ||
43 | void *tomoyo_alloc_element(const unsigned int size); | ||
44 | |||
45 | /* | ||
46 | * Keep the given name on the RAM. | ||
47 | * The RAM is shared, so NEVER try to modify or kfree() the returned name. | ||
48 | */ | ||
49 | const struct tomoyo_path_info *tomoyo_save_name(const char *name); | ||
50 | |||
51 | /* Allocate memory for temporary use (e.g. permission checks). */ | ||
52 | void *tomoyo_alloc(const size_t size); | ||
53 | |||
54 | /* Free memory allocated by tomoyo_alloc(). */ | ||
55 | void tomoyo_free(const void *p); | ||
56 | |||
57 | /* Check for memory usage. */ | ||
58 | int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); | ||
59 | |||
60 | /* Set memory quota. */ | ||
61 | int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); | ||
62 | |||
63 | /* Initialize realpath related code. */ | ||
64 | void __init tomoyo_realpath_init(void); | ||
65 | |||
66 | #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */ | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 2aceebf5f354..dedd97d0c163 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -11,8 +11,6 @@ | |||
11 | 11 | ||
12 | #include <linux/security.h> | 12 | #include <linux/security.h> |
13 | #include "common.h" | 13 | #include "common.h" |
14 | #include "tomoyo.h" | ||
15 | #include "realpath.h" | ||
16 | 14 | ||
17 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | 15 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) |
18 | { | 16 | { |
@@ -23,21 +21,23 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | |||
23 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 21 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
24 | gfp_t gfp) | 22 | gfp_t gfp) |
25 | { | 23 | { |
26 | /* | 24 | struct tomoyo_domain_info *domain = old->security; |
27 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | 25 | new->security = domain; |
28 | * we don't need to duplicate. | 26 | if (domain) |
29 | */ | 27 | atomic_inc(&domain->users); |
30 | new->security = old->security; | ||
31 | return 0; | 28 | return 0; |
32 | } | 29 | } |
33 | 30 | ||
34 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | 31 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) |
35 | { | 32 | { |
36 | /* | 33 | tomoyo_cred_prepare(new, old, 0); |
37 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | 34 | } |
38 | * we don't need to duplicate. | 35 | |
39 | */ | 36 | static void tomoyo_cred_free(struct cred *cred) |
40 | new->security = old->security; | 37 | { |
38 | struct tomoyo_domain_info *domain = cred->security; | ||
39 | if (domain) | ||
40 | atomic_dec(&domain->users); | ||
41 | } | 41 | } |
42 | 42 | ||
43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
@@ -61,6 +61,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | |||
61 | if (!tomoyo_policy_loaded) | 61 | if (!tomoyo_policy_loaded) |
62 | tomoyo_load_policy(bprm->filename); | 62 | tomoyo_load_policy(bprm->filename); |
63 | /* | 63 | /* |
64 | * Release reference to "struct tomoyo_domain_info" stored inside | ||
65 | * "bprm->cred->security". New reference to "struct tomoyo_domain_info" | ||
66 | * stored inside "bprm->cred->security" will be acquired later inside | ||
67 | * tomoyo_find_next_domain(). | ||
68 | */ | ||
69 | atomic_dec(&((struct tomoyo_domain_info *) | ||
70 | bprm->cred->security)->users); | ||
71 | /* | ||
64 | * Tell tomoyo_bprm_check_security() is called for the first time of an | 72 | * Tell tomoyo_bprm_check_security() is called for the first time of an |
65 | * execve operation. | 73 | * execve operation. |
66 | */ | 74 | */ |
@@ -76,8 +84,12 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
76 | * Execute permission is checked against pathname passed to do_execve() | 84 | * Execute permission is checked against pathname passed to do_execve() |
77 | * using current domain. | 85 | * using current domain. |
78 | */ | 86 | */ |
79 | if (!domain) | 87 | if (!domain) { |
80 | return tomoyo_find_next_domain(bprm); | 88 | const int idx = tomoyo_read_lock(); |
89 | const int err = tomoyo_find_next_domain(bprm); | ||
90 | tomoyo_read_unlock(idx); | ||
91 | return err; | ||
92 | } | ||
81 | /* | 93 | /* |
82 | * Read permission is checked against interpreters using next domain. | 94 | * Read permission is checked against interpreters using next domain. |
83 | */ | 95 | */ |
@@ -87,67 +99,56 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
87 | static int tomoyo_path_truncate(struct path *path, loff_t length, | 99 | static int tomoyo_path_truncate(struct path *path, loff_t length, |
88 | unsigned int time_attrs) | 100 | unsigned int time_attrs) |
89 | { | 101 | { |
90 | return tomoyo_check_1path_perm(tomoyo_domain(), | 102 | return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path); |
91 | TOMOYO_TYPE_TRUNCATE_ACL, | ||
92 | path); | ||
93 | } | 103 | } |
94 | 104 | ||
95 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) | 105 | static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) |
96 | { | 106 | { |
97 | struct path path = { parent->mnt, dentry }; | 107 | struct path path = { parent->mnt, dentry }; |
98 | return tomoyo_check_1path_perm(tomoyo_domain(), | 108 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path); |
99 | TOMOYO_TYPE_UNLINK_ACL, | ||
100 | &path); | ||
101 | } | 109 | } |
102 | 110 | ||
103 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, | 111 | static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, |
104 | int mode) | 112 | int mode) |
105 | { | 113 | { |
106 | struct path path = { parent->mnt, dentry }; | 114 | struct path path = { parent->mnt, dentry }; |
107 | return tomoyo_check_1path_perm(tomoyo_domain(), | 115 | return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path); |
108 | TOMOYO_TYPE_MKDIR_ACL, | ||
109 | &path); | ||
110 | } | 116 | } |
111 | 117 | ||
112 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) | 118 | static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) |
113 | { | 119 | { |
114 | struct path path = { parent->mnt, dentry }; | 120 | struct path path = { parent->mnt, dentry }; |
115 | return tomoyo_check_1path_perm(tomoyo_domain(), | 121 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path); |
116 | TOMOYO_TYPE_RMDIR_ACL, | ||
117 | &path); | ||
118 | } | 122 | } |
119 | 123 | ||
120 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, | 124 | static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, |
121 | const char *old_name) | 125 | const char *old_name) |
122 | { | 126 | { |
123 | struct path path = { parent->mnt, dentry }; | 127 | struct path path = { parent->mnt, dentry }; |
124 | return tomoyo_check_1path_perm(tomoyo_domain(), | 128 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path); |
125 | TOMOYO_TYPE_SYMLINK_ACL, | ||
126 | &path); | ||
127 | } | 129 | } |
128 | 130 | ||
129 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, | 131 | static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, |
130 | int mode, unsigned int dev) | 132 | int mode, unsigned int dev) |
131 | { | 133 | { |
132 | struct path path = { parent->mnt, dentry }; | 134 | struct path path = { parent->mnt, dentry }; |
133 | int type = TOMOYO_TYPE_CREATE_ACL; | 135 | int type = TOMOYO_TYPE_CREATE; |
134 | 136 | ||
135 | switch (mode & S_IFMT) { | 137 | switch (mode & S_IFMT) { |
136 | case S_IFCHR: | 138 | case S_IFCHR: |
137 | type = TOMOYO_TYPE_MKCHAR_ACL; | 139 | type = TOMOYO_TYPE_MKCHAR; |
138 | break; | 140 | break; |
139 | case S_IFBLK: | 141 | case S_IFBLK: |
140 | type = TOMOYO_TYPE_MKBLOCK_ACL; | 142 | type = TOMOYO_TYPE_MKBLOCK; |
141 | break; | 143 | break; |
142 | case S_IFIFO: | 144 | case S_IFIFO: |
143 | type = TOMOYO_TYPE_MKFIFO_ACL; | 145 | type = TOMOYO_TYPE_MKFIFO; |
144 | break; | 146 | break; |
145 | case S_IFSOCK: | 147 | case S_IFSOCK: |
146 | type = TOMOYO_TYPE_MKSOCK_ACL; | 148 | type = TOMOYO_TYPE_MKSOCK; |
147 | break; | 149 | break; |
148 | } | 150 | } |
149 | return tomoyo_check_1path_perm(tomoyo_domain(), | 151 | return tomoyo_path_perm(type, &path); |
150 | type, &path); | ||
151 | } | 152 | } |
152 | 153 | ||
153 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | 154 | static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, |
@@ -155,9 +156,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, | |||
155 | { | 156 | { |
156 | struct path path1 = { new_dir->mnt, old_dentry }; | 157 | struct path path1 = { new_dir->mnt, old_dentry }; |
157 | struct path path2 = { new_dir->mnt, new_dentry }; | 158 | struct path path2 = { new_dir->mnt, new_dentry }; |
158 | return tomoyo_check_2path_perm(tomoyo_domain(), | 159 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
159 | TOMOYO_TYPE_LINK_ACL, | ||
160 | &path1, &path2); | ||
161 | } | 160 | } |
162 | 161 | ||
163 | static int tomoyo_path_rename(struct path *old_parent, | 162 | static int tomoyo_path_rename(struct path *old_parent, |
@@ -167,16 +166,14 @@ static int tomoyo_path_rename(struct path *old_parent, | |||
167 | { | 166 | { |
168 | struct path path1 = { old_parent->mnt, old_dentry }; | 167 | struct path path1 = { old_parent->mnt, old_dentry }; |
169 | struct path path2 = { new_parent->mnt, new_dentry }; | 168 | struct path path2 = { new_parent->mnt, new_dentry }; |
170 | return tomoyo_check_2path_perm(tomoyo_domain(), | 169 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
171 | TOMOYO_TYPE_RENAME_ACL, | ||
172 | &path1, &path2); | ||
173 | } | 170 | } |
174 | 171 | ||
175 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | 172 | static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, |
176 | unsigned long arg) | 173 | unsigned long arg) |
177 | { | 174 | { |
178 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) | 175 | if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) |
179 | return tomoyo_check_rewrite_permission(tomoyo_domain(), file); | 176 | return tomoyo_check_rewrite_permission(file); |
180 | return 0; | 177 | return 0; |
181 | } | 178 | } |
182 | 179 | ||
@@ -189,6 +186,51 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
189 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 186 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
190 | } | 187 | } |
191 | 188 | ||
189 | static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, | ||
190 | unsigned long arg) | ||
191 | { | ||
192 | return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path); | ||
193 | } | ||
194 | |||
195 | static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | ||
196 | mode_t mode) | ||
197 | { | ||
198 | struct path path = { mnt, dentry }; | ||
199 | return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path); | ||
200 | } | ||
201 | |||
202 | static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) | ||
203 | { | ||
204 | int error = 0; | ||
205 | if (uid != (uid_t) -1) | ||
206 | error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path); | ||
207 | if (!error && gid != (gid_t) -1) | ||
208 | error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path); | ||
209 | return error; | ||
210 | } | ||
211 | |||
212 | static int tomoyo_path_chroot(struct path *path) | ||
213 | { | ||
214 | return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path); | ||
215 | } | ||
216 | |||
217 | static int tomoyo_sb_mount(char *dev_name, struct path *path, | ||
218 | char *type, unsigned long flags, void *data) | ||
219 | { | ||
220 | return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path); | ||
221 | } | ||
222 | |||
223 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) | ||
224 | { | ||
225 | struct path path = { mnt, mnt->mnt_root }; | ||
226 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path); | ||
227 | } | ||
228 | |||
229 | static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) | ||
230 | { | ||
231 | return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); | ||
232 | } | ||
233 | |||
192 | /* | 234 | /* |
193 | * tomoyo_security_ops is a "struct security_operations" which is used for | 235 | * tomoyo_security_ops is a "struct security_operations" which is used for |
194 | * registering TOMOYO. | 236 | * registering TOMOYO. |
@@ -198,6 +240,7 @@ static struct security_operations tomoyo_security_ops = { | |||
198 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | 240 | .cred_alloc_blank = tomoyo_cred_alloc_blank, |
199 | .cred_prepare = tomoyo_cred_prepare, | 241 | .cred_prepare = tomoyo_cred_prepare, |
200 | .cred_transfer = tomoyo_cred_transfer, | 242 | .cred_transfer = tomoyo_cred_transfer, |
243 | .cred_free = tomoyo_cred_free, | ||
201 | .bprm_set_creds = tomoyo_bprm_set_creds, | 244 | .bprm_set_creds = tomoyo_bprm_set_creds, |
202 | .bprm_check_security = tomoyo_bprm_check_security, | 245 | .bprm_check_security = tomoyo_bprm_check_security, |
203 | .file_fcntl = tomoyo_file_fcntl, | 246 | .file_fcntl = tomoyo_file_fcntl, |
@@ -210,8 +253,18 @@ static struct security_operations tomoyo_security_ops = { | |||
210 | .path_mknod = tomoyo_path_mknod, | 253 | .path_mknod = tomoyo_path_mknod, |
211 | .path_link = tomoyo_path_link, | 254 | .path_link = tomoyo_path_link, |
212 | .path_rename = tomoyo_path_rename, | 255 | .path_rename = tomoyo_path_rename, |
256 | .file_ioctl = tomoyo_file_ioctl, | ||
257 | .path_chmod = tomoyo_path_chmod, | ||
258 | .path_chown = tomoyo_path_chown, | ||
259 | .path_chroot = tomoyo_path_chroot, | ||
260 | .sb_mount = tomoyo_sb_mount, | ||
261 | .sb_umount = tomoyo_sb_umount, | ||
262 | .sb_pivotroot = tomoyo_sb_pivotroot, | ||
213 | }; | 263 | }; |
214 | 264 | ||
265 | /* Lock for GC. */ | ||
266 | struct srcu_struct tomoyo_ss; | ||
267 | |||
215 | static int __init tomoyo_init(void) | 268 | static int __init tomoyo_init(void) |
216 | { | 269 | { |
217 | struct cred *cred = (struct cred *) current_cred(); | 270 | struct cred *cred = (struct cred *) current_cred(); |
@@ -219,7 +272,8 @@ static int __init tomoyo_init(void) | |||
219 | if (!security_module_enable(&tomoyo_security_ops)) | 272 | if (!security_module_enable(&tomoyo_security_ops)) |
220 | return 0; | 273 | return 0; |
221 | /* register ourselves with the security framework */ | 274 | /* register ourselves with the security framework */ |
222 | if (register_security(&tomoyo_security_ops)) | 275 | if (register_security(&tomoyo_security_ops) || |
276 | init_srcu_struct(&tomoyo_ss)) | ||
223 | panic("Failure registering TOMOYO Linux"); | 277 | panic("Failure registering TOMOYO Linux"); |
224 | printk(KERN_INFO "TOMOYO Linux initialized\n"); | 278 | printk(KERN_INFO "TOMOYO Linux initialized\n"); |
225 | cred->security = &tomoyo_kernel_domain; | 279 | cred->security = &tomoyo_kernel_domain; |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h deleted file mode 100644 index ed758325b1ae..000000000000 --- a/security/tomoyo/tomoyo.h +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | /* | ||
2 | * security/tomoyo/tomoyo.h | ||
3 | * | ||
4 | * Implementation of the Domain-Based Mandatory Access Control. | ||
5 | * | ||
6 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
7 | * | ||
8 | * Version: 2.2.0 2009/04/01 | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _SECURITY_TOMOYO_TOMOYO_H | ||
13 | #define _SECURITY_TOMOYO_TOMOYO_H | ||
14 | |||
15 | struct tomoyo_path_info; | ||
16 | struct path; | ||
17 | struct inode; | ||
18 | struct linux_binprm; | ||
19 | struct pt_regs; | ||
20 | |||
21 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | ||
22 | const struct tomoyo_path_info *filename); | ||
23 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | ||
24 | struct path *path, const int flag); | ||
25 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | ||
26 | const u8 operation, struct path *path); | ||
27 | int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, | ||
28 | const u8 operation, struct path *path1, | ||
29 | struct path *path2); | ||
30 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | ||
31 | struct file *filp); | ||
32 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | ||
33 | |||
34 | /* Index numbers for Access Controls. */ | ||
35 | |||
36 | #define TOMOYO_TYPE_SINGLE_PATH_ACL 0 | ||
37 | #define TOMOYO_TYPE_DOUBLE_PATH_ACL 1 | ||
38 | |||
39 | /* Index numbers for File Controls. */ | ||
40 | |||
41 | /* | ||
42 | * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set | ||
43 | * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and | ||
44 | * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set. | ||
45 | * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or | ||
46 | * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are | ||
47 | * automatically cleared if TYPE_READ_WRITE_ACL is cleared. | ||
48 | */ | ||
49 | |||
50 | #define TOMOYO_TYPE_READ_WRITE_ACL 0 | ||
51 | #define TOMOYO_TYPE_EXECUTE_ACL 1 | ||
52 | #define TOMOYO_TYPE_READ_ACL 2 | ||
53 | #define TOMOYO_TYPE_WRITE_ACL 3 | ||
54 | #define TOMOYO_TYPE_CREATE_ACL 4 | ||
55 | #define TOMOYO_TYPE_UNLINK_ACL 5 | ||
56 | #define TOMOYO_TYPE_MKDIR_ACL 6 | ||
57 | #define TOMOYO_TYPE_RMDIR_ACL 7 | ||
58 | #define TOMOYO_TYPE_MKFIFO_ACL 8 | ||
59 | #define TOMOYO_TYPE_MKSOCK_ACL 9 | ||
60 | #define TOMOYO_TYPE_MKBLOCK_ACL 10 | ||
61 | #define TOMOYO_TYPE_MKCHAR_ACL 11 | ||
62 | #define TOMOYO_TYPE_TRUNCATE_ACL 12 | ||
63 | #define TOMOYO_TYPE_SYMLINK_ACL 13 | ||
64 | #define TOMOYO_TYPE_REWRITE_ACL 14 | ||
65 | #define TOMOYO_MAX_SINGLE_PATH_OPERATION 15 | ||
66 | |||
67 | #define TOMOYO_TYPE_LINK_ACL 0 | ||
68 | #define TOMOYO_TYPE_RENAME_ACL 1 | ||
69 | #define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2 | ||
70 | |||
71 | #define TOMOYO_DOMAINPOLICY 0 | ||
72 | #define TOMOYO_EXCEPTIONPOLICY 1 | ||
73 | #define TOMOYO_DOMAIN_STATUS 2 | ||
74 | #define TOMOYO_PROCESS_STATUS 3 | ||
75 | #define TOMOYO_MEMINFO 4 | ||
76 | #define TOMOYO_SELFDOMAIN 5 | ||
77 | #define TOMOYO_VERSION 6 | ||
78 | #define TOMOYO_PROFILE 7 | ||
79 | #define TOMOYO_MANAGER 8 | ||
80 | |||
81 | extern struct tomoyo_domain_info tomoyo_kernel_domain; | ||
82 | |||
83 | static inline struct tomoyo_domain_info *tomoyo_domain(void) | ||
84 | { | ||
85 | return current_cred()->security; | ||
86 | } | ||
87 | |||
88 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | ||
89 | *task) | ||
90 | { | ||
91 | return task_cred_xxx(task, security); | ||
92 | } | ||
93 | |||
94 | #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ | ||