diff options
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r-- | security/tomoyo/common.c | 374 |
1 files changed, 146 insertions, 228 deletions
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". |