diff options
Diffstat (limited to 'security/tomoyo/file.c')
-rw-r--r-- | security/tomoyo/file.c | 234 |
1 files changed, 99 insertions, 135 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 84c821a245ca..f4a27714e077 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -215,38 +215,34 @@ static LIST_HEAD(tomoyo_globally_readable_list); | |||
215 | static int tomoyo_update_globally_readable_entry(const char *filename, | 215 | static int tomoyo_update_globally_readable_entry(const char *filename, |
216 | const bool is_delete) | 216 | const bool is_delete) |
217 | { | 217 | { |
218 | struct tomoyo_globally_readable_file_entry *new_entry; | 218 | struct tomoyo_globally_readable_file_entry *entry = NULL; |
219 | struct tomoyo_globally_readable_file_entry *ptr; | 219 | struct tomoyo_globally_readable_file_entry *ptr; |
220 | const struct tomoyo_path_info *saved_filename; | 220 | const struct tomoyo_path_info *saved_filename; |
221 | int error = -ENOMEM; | 221 | int error = is_delete ? -ENOENT : -ENOMEM; |
222 | 222 | ||
223 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) | 223 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) |
224 | return -EINVAL; | 224 | return -EINVAL; |
225 | saved_filename = tomoyo_save_name(filename); | 225 | saved_filename = tomoyo_save_name(filename); |
226 | if (!saved_filename) | 226 | if (!saved_filename) |
227 | return -ENOMEM; | 227 | return -ENOMEM; |
228 | new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); | 228 | if (!is_delete) |
229 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
229 | mutex_lock(&tomoyo_policy_lock); | 230 | mutex_lock(&tomoyo_policy_lock); |
230 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { | 231 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { |
231 | if (ptr->filename != saved_filename) | 232 | if (ptr->filename != saved_filename) |
232 | continue; | 233 | continue; |
233 | ptr->is_deleted = is_delete; | 234 | ptr->is_deleted = is_delete; |
234 | error = 0; | 235 | error = 0; |
235 | goto out; | 236 | break; |
236 | } | 237 | } |
237 | if (is_delete) { | 238 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
238 | error = -ENOENT; | 239 | entry->filename = saved_filename; |
239 | goto out; | 240 | list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); |
241 | entry = NULL; | ||
242 | error = 0; | ||
240 | } | 243 | } |
241 | if (!tomoyo_memory_ok(new_entry)) | ||
242 | goto out; | ||
243 | new_entry->filename = saved_filename; | ||
244 | list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list); | ||
245 | new_entry = NULL; | ||
246 | error = 0; | ||
247 | out: | ||
248 | mutex_unlock(&tomoyo_policy_lock); | 244 | mutex_unlock(&tomoyo_policy_lock); |
249 | kfree(new_entry); | 245 | kfree(entry); |
250 | return error; | 246 | return error; |
251 | } | 247 | } |
252 | 248 | ||
@@ -364,38 +360,35 @@ static LIST_HEAD(tomoyo_pattern_list); | |||
364 | static int tomoyo_update_file_pattern_entry(const char *pattern, | 360 | static int tomoyo_update_file_pattern_entry(const char *pattern, |
365 | const bool is_delete) | 361 | const bool is_delete) |
366 | { | 362 | { |
367 | struct tomoyo_pattern_entry *new_entry; | 363 | struct tomoyo_pattern_entry *entry = NULL; |
368 | struct tomoyo_pattern_entry *ptr; | 364 | struct tomoyo_pattern_entry *ptr; |
369 | const struct tomoyo_path_info *saved_pattern; | 365 | const struct tomoyo_path_info *saved_pattern; |
370 | int error = -ENOMEM; | 366 | int error = is_delete ? -ENOENT : -ENOMEM; |
371 | 367 | ||
372 | if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) | ||
373 | return -EINVAL; | ||
374 | saved_pattern = tomoyo_save_name(pattern); | 368 | saved_pattern = tomoyo_save_name(pattern); |
375 | if (!saved_pattern) | 369 | if (!saved_pattern) |
376 | return -ENOMEM; | 370 | return error; |
377 | new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); | 371 | if (!saved_pattern->is_patterned) |
372 | goto out; | ||
373 | if (!is_delete) | ||
374 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
378 | mutex_lock(&tomoyo_policy_lock); | 375 | mutex_lock(&tomoyo_policy_lock); |
379 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | 376 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { |
380 | if (saved_pattern != ptr->pattern) | 377 | if (saved_pattern != ptr->pattern) |
381 | continue; | 378 | continue; |
382 | ptr->is_deleted = is_delete; | 379 | ptr->is_deleted = is_delete; |
383 | error = 0; | 380 | error = 0; |
384 | goto out; | 381 | break; |
385 | } | 382 | } |
386 | if (is_delete) { | 383 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
387 | error = -ENOENT; | 384 | entry->pattern = saved_pattern; |
388 | goto out; | 385 | list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); |
386 | entry = NULL; | ||
387 | error = 0; | ||
389 | } | 388 | } |
390 | if (!tomoyo_memory_ok(new_entry)) | ||
391 | goto out; | ||
392 | new_entry->pattern = saved_pattern; | ||
393 | list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list); | ||
394 | new_entry = NULL; | ||
395 | error = 0; | ||
396 | out: | ||
397 | mutex_unlock(&tomoyo_policy_lock); | 389 | mutex_unlock(&tomoyo_policy_lock); |
398 | kfree(new_entry); | 390 | out: |
391 | kfree(entry); | ||
399 | return error; | 392 | return error; |
400 | } | 393 | } |
401 | 394 | ||
@@ -518,37 +511,34 @@ static LIST_HEAD(tomoyo_no_rewrite_list); | |||
518 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | 511 | static int tomoyo_update_no_rewrite_entry(const char *pattern, |
519 | const bool is_delete) | 512 | const bool is_delete) |
520 | { | 513 | { |
521 | struct tomoyo_no_rewrite_entry *new_entry, *ptr; | 514 | struct tomoyo_no_rewrite_entry *entry = NULL; |
515 | struct tomoyo_no_rewrite_entry *ptr; | ||
522 | const struct tomoyo_path_info *saved_pattern; | 516 | const struct tomoyo_path_info *saved_pattern; |
523 | int error = -ENOMEM; | 517 | int error = is_delete ? -ENOENT : -ENOMEM; |
524 | 518 | ||
525 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) | 519 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) |
526 | return -EINVAL; | 520 | return -EINVAL; |
527 | saved_pattern = tomoyo_save_name(pattern); | 521 | saved_pattern = tomoyo_save_name(pattern); |
528 | if (!saved_pattern) | 522 | if (!saved_pattern) |
529 | return -ENOMEM; | 523 | return error; |
530 | new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); | 524 | if (!is_delete) |
525 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
531 | mutex_lock(&tomoyo_policy_lock); | 526 | mutex_lock(&tomoyo_policy_lock); |
532 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | 527 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { |
533 | if (ptr->pattern != saved_pattern) | 528 | if (ptr->pattern != saved_pattern) |
534 | continue; | 529 | continue; |
535 | ptr->is_deleted = is_delete; | 530 | ptr->is_deleted = is_delete; |
536 | error = 0; | 531 | error = 0; |
537 | goto out; | 532 | break; |
538 | } | 533 | } |
539 | if (is_delete) { | 534 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
540 | error = -ENOENT; | 535 | entry->pattern = saved_pattern; |
541 | goto out; | 536 | list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); |
537 | entry = NULL; | ||
538 | error = 0; | ||
542 | } | 539 | } |
543 | if (!tomoyo_memory_ok(new_entry)) | ||
544 | goto out; | ||
545 | new_entry->pattern = saved_pattern; | ||
546 | list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list); | ||
547 | new_entry = NULL; | ||
548 | error = 0; | ||
549 | out: | ||
550 | mutex_unlock(&tomoyo_policy_lock); | 540 | mutex_unlock(&tomoyo_policy_lock); |
551 | kfree(new_entry); | 541 | kfree(entry); |
552 | return error; | 542 | return error; |
553 | } | 543 | } |
554 | 544 | ||
@@ -869,8 +859,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
869 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); | 859 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); |
870 | const struct tomoyo_path_info *saved_filename; | 860 | const struct tomoyo_path_info *saved_filename; |
871 | struct tomoyo_acl_info *ptr; | 861 | struct tomoyo_acl_info *ptr; |
872 | struct tomoyo_single_path_acl_record *acl; | 862 | struct tomoyo_single_path_acl_record *entry = NULL; |
873 | int error = -ENOMEM; | 863 | int error = is_delete ? -ENOENT : -ENOMEM; |
874 | const u32 perm = 1 << type; | 864 | const u32 perm = 1 << type; |
875 | 865 | ||
876 | if (!domain) | 866 | if (!domain) |
@@ -880,67 +870,55 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
880 | saved_filename = tomoyo_save_name(filename); | 870 | saved_filename = tomoyo_save_name(filename); |
881 | if (!saved_filename) | 871 | if (!saved_filename) |
882 | return -ENOMEM; | 872 | return -ENOMEM; |
873 | if (!is_delete) | ||
874 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
883 | mutex_lock(&tomoyo_policy_lock); | 875 | mutex_lock(&tomoyo_policy_lock); |
884 | if (is_delete) | ||
885 | goto delete; | ||
886 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 876 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
877 | struct tomoyo_single_path_acl_record *acl = | ||
878 | container_of(ptr, struct tomoyo_single_path_acl_record, | ||
879 | head); | ||
887 | if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) | 880 | if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) |
888 | continue; | 881 | continue; |
889 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
890 | head); | ||
891 | if (acl->filename != saved_filename) | 882 | if (acl->filename != saved_filename) |
892 | continue; | 883 | continue; |
893 | if (perm <= 0xFFFF) | 884 | if (is_delete) { |
894 | acl->perm |= perm; | 885 | if (perm <= 0xFFFF) |
895 | else | 886 | acl->perm &= ~perm; |
896 | acl->perm_high |= (perm >> 16); | 887 | else |
897 | if ((acl->perm & rw_mask) == rw_mask) | 888 | acl->perm_high &= ~(perm >> 16); |
898 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 889 | if ((acl->perm & rw_mask) != rw_mask) |
899 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 890 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); |
900 | acl->perm |= rw_mask; | 891 | else if (!(acl->perm & |
892 | (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | ||
893 | acl->perm &= ~rw_mask; | ||
894 | } else { | ||
895 | if (perm <= 0xFFFF) | ||
896 | acl->perm |= perm; | ||
897 | else | ||
898 | acl->perm_high |= (perm >> 16); | ||
899 | if ((acl->perm & rw_mask) == rw_mask) | ||
900 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; | ||
901 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | ||
902 | acl->perm |= rw_mask; | ||
903 | } | ||
901 | error = 0; | 904 | error = 0; |
902 | goto out; | 905 | break; |
903 | } | ||
904 | /* Not found. Append it to the tail. */ | ||
905 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | ||
906 | if (!tomoyo_memory_ok(acl)) { | ||
907 | kfree(acl); | ||
908 | acl = NULL; | ||
909 | goto out; | ||
910 | } | 906 | } |
911 | acl->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; | 907 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
912 | if (perm <= 0xFFFF) | 908 | entry->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; |
913 | acl->perm = perm; | ||
914 | else | ||
915 | acl->perm_high = (perm >> 16); | ||
916 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | ||
917 | acl->perm |= rw_mask; | ||
918 | acl->filename = saved_filename; | ||
919 | list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); | ||
920 | error = 0; | ||
921 | goto out; | ||
922 | delete: | ||
923 | error = -ENOENT; | ||
924 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
925 | if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
926 | continue; | ||
927 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
928 | head); | ||
929 | if (acl->filename != saved_filename) | ||
930 | continue; | ||
931 | if (perm <= 0xFFFF) | 909 | if (perm <= 0xFFFF) |
932 | acl->perm &= ~perm; | 910 | entry->perm = perm; |
933 | else | 911 | else |
934 | acl->perm_high &= ~(perm >> 16); | 912 | entry->perm_high = (perm >> 16); |
935 | if ((acl->perm & rw_mask) != rw_mask) | 913 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) |
936 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); | 914 | entry->perm |= rw_mask; |
937 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | 915 | entry->filename = saved_filename; |
938 | acl->perm &= ~rw_mask; | 916 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); |
917 | entry = NULL; | ||
939 | error = 0; | 918 | error = 0; |
940 | break; | ||
941 | } | 919 | } |
942 | out: | ||
943 | mutex_unlock(&tomoyo_policy_lock); | 920 | mutex_unlock(&tomoyo_policy_lock); |
921 | kfree(entry); | ||
944 | return error; | 922 | return error; |
945 | } | 923 | } |
946 | 924 | ||
@@ -965,8 +943,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | |||
965 | const struct tomoyo_path_info *saved_filename1; | 943 | const struct tomoyo_path_info *saved_filename1; |
966 | const struct tomoyo_path_info *saved_filename2; | 944 | const struct tomoyo_path_info *saved_filename2; |
967 | struct tomoyo_acl_info *ptr; | 945 | struct tomoyo_acl_info *ptr; |
968 | struct tomoyo_double_path_acl_record *acl; | 946 | struct tomoyo_double_path_acl_record *entry = NULL; |
969 | int error = -ENOMEM; | 947 | int error = is_delete ? -ENOENT : -ENOMEM; |
970 | const u8 perm = 1 << type; | 948 | const u8 perm = 1 << type; |
971 | 949 | ||
972 | if (!domain) | 950 | if (!domain) |
@@ -977,52 +955,38 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | |||
977 | saved_filename1 = tomoyo_save_name(filename1); | 955 | saved_filename1 = tomoyo_save_name(filename1); |
978 | saved_filename2 = tomoyo_save_name(filename2); | 956 | saved_filename2 = tomoyo_save_name(filename2); |
979 | if (!saved_filename1 || !saved_filename2) | 957 | if (!saved_filename1 || !saved_filename2) |
980 | return -ENOMEM; | 958 | goto out; |
959 | if (!is_delete) | ||
960 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
981 | mutex_lock(&tomoyo_policy_lock); | 961 | mutex_lock(&tomoyo_policy_lock); |
982 | if (is_delete) | ||
983 | goto delete; | ||
984 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 962 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
963 | struct tomoyo_double_path_acl_record *acl = | ||
964 | container_of(ptr, struct tomoyo_double_path_acl_record, | ||
965 | head); | ||
985 | if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) | 966 | if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) |
986 | continue; | 967 | continue; |
987 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
988 | head); | ||
989 | if (acl->filename1 != saved_filename1 || | 968 | if (acl->filename1 != saved_filename1 || |
990 | acl->filename2 != saved_filename2) | 969 | acl->filename2 != saved_filename2) |
991 | continue; | 970 | continue; |
992 | acl->perm |= perm; | 971 | if (is_delete) |
972 | acl->perm &= ~perm; | ||
973 | else | ||
974 | acl->perm |= perm; | ||
993 | error = 0; | 975 | error = 0; |
994 | goto out; | 976 | break; |
995 | } | ||
996 | /* Not found. Append it to the tail. */ | ||
997 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | ||
998 | if (!tomoyo_memory_ok(acl)) { | ||
999 | kfree(acl); | ||
1000 | acl = NULL; | ||
1001 | goto out; | ||
1002 | } | 977 | } |
1003 | acl->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; | 978 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
1004 | acl->perm = perm; | 979 | entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; |
1005 | acl->filename1 = saved_filename1; | 980 | entry->perm = perm; |
1006 | acl->filename2 = saved_filename2; | 981 | entry->filename1 = saved_filename1; |
1007 | list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); | 982 | entry->filename2 = saved_filename2; |
1008 | error = 0; | 983 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); |
1009 | goto out; | 984 | entry = NULL; |
1010 | delete: | ||
1011 | error = -ENOENT; | ||
1012 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
1013 | if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
1014 | continue; | ||
1015 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
1016 | head); | ||
1017 | if (acl->filename1 != saved_filename1 || | ||
1018 | acl->filename2 != saved_filename2) | ||
1019 | continue; | ||
1020 | acl->perm &= ~perm; | ||
1021 | error = 0; | 985 | error = 0; |
1022 | break; | ||
1023 | } | 986 | } |
1024 | out: | ||
1025 | mutex_unlock(&tomoyo_policy_lock); | 987 | mutex_unlock(&tomoyo_policy_lock); |
988 | out: | ||
989 | kfree(entry); | ||
1026 | return error; | 990 | return error; |
1027 | } | 991 | } |
1028 | 992 | ||