aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo/file.c
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2010-06-12 07:46:22 -0400
committerJames Morris <jmorris@namei.org>2010-08-02 01:34:28 -0400
commit237ab459f12cb98eadd3fe7b85343e183a1076a4 (patch)
treef2835e2945016beb4e29b6a2ed8f9d372dc1b412 /security/tomoyo/file.c
parent927942aabbbe506bf9bc70a16dc5460ecc64c148 (diff)
TOMOYO: Use callback for updating entries.
Use common "struct list_head" + "bool" + "u8" structure and use common code for elements using that structure. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/file.c')
-rw-r--r--security/tomoyo/file.c349
1 files changed, 153 insertions, 196 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 8e51348d022e..b826058c72e9 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -665,50 +665,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
665} 665}
666 666
667/** 667/**
668 * tomoyo_update_file_acl - Update file's read/write/execute ACL.
669 *
670 * @perm: Permission (between 1 to 7).
671 * @filename: Filename.
672 * @domain: Pointer to "struct tomoyo_domain_info".
673 * @is_delete: True if it is a delete request.
674 *
675 * Returns 0 on success, negative value otherwise.
676 *
677 * This is legacy support interface for older policy syntax.
678 * Current policy syntax uses "allow_read/write" instead of "6",
679 * "allow_read" instead of "4", "allow_write" instead of "2",
680 * "allow_execute" instead of "1".
681 *
682 * Caller holds tomoyo_read_lock().
683 */
684static int tomoyo_update_file_acl(u8 perm, const char *filename,
685 struct tomoyo_domain_info * const domain,
686 const bool is_delete)
687{
688 if (perm > 7 || !perm) {
689 printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
690 __func__, perm, filename);
691 return -EINVAL;
692 }
693 if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
694 /*
695 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
696 * directory permissions.
697 */
698 return 0;
699 if (perm & 4)
700 tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain,
701 is_delete);
702 if (perm & 2)
703 tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain,
704 is_delete);
705 if (perm & 1)
706 tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain,
707 is_delete);
708 return 0;
709}
710
711/**
712 * tomoyo_path_acl - Check permission for single path operation. 668 * tomoyo_path_acl - Check permission for single path operation.
713 * 669 *
714 * @r: Pointer to "struct tomoyo_request_info". 670 * @r: Pointer to "struct tomoyo_request_info".
@@ -797,6 +753,40 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r,
797 return error; 753 return error;
798} 754}
799 755
756static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
757 const struct tomoyo_acl_info *b)
758{
759 const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
760 const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
761 return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
762 tomoyo_is_same_name_union(&p1->name, &p2->name);
763}
764
765static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
766 struct tomoyo_acl_info *b,
767 const bool is_delete)
768{
769 u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
770 ->perm;
771 u16 perm = *a_perm;
772 const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
773 if (is_delete) {
774 perm &= ~b_perm;
775 if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
776 perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
777 else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
778 perm &= ~TOMOYO_RW_MASK;
779 } else {
780 perm |= b_perm;
781 if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
782 perm |= (1 << TOMOYO_TYPE_READ_WRITE);
783 else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
784 perm |= TOMOYO_RW_MASK;
785 }
786 *a_perm = perm;
787 return !perm;
788}
789
800/** 790/**
801 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 791 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
802 * 792 *
@@ -810,63 +800,56 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r,
810 * Caller holds tomoyo_read_lock(). 800 * Caller holds tomoyo_read_lock().
811 */ 801 */
812static int tomoyo_update_path_acl(const u8 type, const char *filename, 802static int tomoyo_update_path_acl(const u8 type, const char *filename,
813 struct tomoyo_domain_info *const domain, 803 struct tomoyo_domain_info * const domain,
814 const bool is_delete) 804 const bool is_delete)
815{ 805{
816 static const u16 tomoyo_rw_mask =
817 (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
818 const u16 perm = 1 << type;
819 struct tomoyo_acl_info *ptr;
820 struct tomoyo_path_acl e = { 806 struct tomoyo_path_acl e = {
821 .head.type = TOMOYO_TYPE_PATH_ACL, 807 .head.type = TOMOYO_TYPE_PATH_ACL,
822 .perm = perm 808 .perm = 1 << type
823 }; 809 };
824 int error = is_delete ? -ENOENT : -ENOMEM; 810 int error;
825 811 if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
826 if (type == TOMOYO_TYPE_READ_WRITE) 812 e.perm |= TOMOYO_RW_MASK;
827 e.perm |= tomoyo_rw_mask;
828 if (!domain)
829 return -EINVAL;
830 if (!tomoyo_parse_name_union(filename, &e.name)) 813 if (!tomoyo_parse_name_union(filename, &e.name))
831 return -EINVAL; 814 return -EINVAL;
832 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 815 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
833 goto out; 816 tomoyo_same_path_acl,
834 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 817 tomoyo_merge_path_acl);
835 struct tomoyo_path_acl *acl =
836 container_of(ptr, struct tomoyo_path_acl, head);
837 if (!tomoyo_is_same_path_acl(acl, &e))
838 continue;
839 if (is_delete) {
840 acl->perm &= ~perm;
841 if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
842 acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
843 else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
844 acl->perm &= ~tomoyo_rw_mask;
845 } else {
846 acl->perm |= perm;
847 if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
848 acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
849 else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
850 acl->perm |= tomoyo_rw_mask;
851 }
852 error = 0;
853 break;
854 }
855 if (!is_delete && error) {
856 struct tomoyo_path_acl *entry =
857 tomoyo_commit_ok(&e, sizeof(e));
858 if (entry) {
859 list_add_tail_rcu(&entry->head.list,
860 &domain->acl_info_list);
861 error = 0;
862 }
863 }
864 mutex_unlock(&tomoyo_policy_lock);
865 out:
866 tomoyo_put_name_union(&e.name); 818 tomoyo_put_name_union(&e.name);
867 return error; 819 return error;
868} 820}
869 821
822static bool tomoyo_same_path_number3_acl(const struct tomoyo_acl_info *a,
823 const struct tomoyo_acl_info *b)
824{
825 const struct tomoyo_path_number3_acl *p1 = container_of(a, typeof(*p1),
826 head);
827 const struct tomoyo_path_number3_acl *p2 = container_of(b, typeof(*p2),
828 head);
829 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
830 && tomoyo_is_same_name_union(&p1->name, &p2->name)
831 && tomoyo_is_same_number_union(&p1->mode, &p2->mode)
832 && tomoyo_is_same_number_union(&p1->major, &p2->major)
833 && tomoyo_is_same_number_union(&p1->minor, &p2->minor);
834}
835
836static bool tomoyo_merge_path_number3_acl(struct tomoyo_acl_info *a,
837 struct tomoyo_acl_info *b,
838 const bool is_delete)
839{
840 u8 *const a_perm = &container_of(a, struct tomoyo_path_number3_acl,
841 head)->perm;
842 u8 perm = *a_perm;
843 const u8 b_perm = container_of(b, struct tomoyo_path_number3_acl, head)
844 ->perm;
845 if (is_delete)
846 perm &= ~b_perm;
847 else
848 perm |= b_perm;
849 *a_perm = perm;
850 return !perm;
851}
852
870/** 853/**
871 * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. 854 * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list.
872 * 855 *
@@ -879,20 +862,17 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
879 * @is_delete: True if it is a delete request. 862 * @is_delete: True if it is a delete request.
880 * 863 *
881 * Returns 0 on success, negative value otherwise. 864 * Returns 0 on success, negative value otherwise.
865 *
866 * Caller holds tomoyo_read_lock().
882 */ 867 */
883static inline int tomoyo_update_path_number3_acl(const u8 type, 868static int tomoyo_update_path_number3_acl(const u8 type, const char *filename,
884 const char *filename, 869 char *mode, char *major, char *minor,
885 char *mode, 870 struct tomoyo_domain_info * const
886 char *major, char *minor, 871 domain, const bool is_delete)
887 struct tomoyo_domain_info *
888 const domain,
889 const bool is_delete)
890{ 872{
891 const u8 perm = 1 << type;
892 struct tomoyo_acl_info *ptr;
893 struct tomoyo_path_number3_acl e = { 873 struct tomoyo_path_number3_acl e = {
894 .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, 874 .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL,
895 .perm = perm 875 .perm = 1 << type
896 }; 876 };
897 int error = is_delete ? -ENOENT : -ENOMEM; 877 int error = is_delete ? -ENOENT : -ENOMEM;
898 if (!tomoyo_parse_name_union(filename, &e.name) || 878 if (!tomoyo_parse_name_union(filename, &e.name) ||
@@ -900,30 +880,9 @@ static inline int tomoyo_update_path_number3_acl(const u8 type,
900 !tomoyo_parse_number_union(major, &e.major) || 880 !tomoyo_parse_number_union(major, &e.major) ||
901 !tomoyo_parse_number_union(minor, &e.minor)) 881 !tomoyo_parse_number_union(minor, &e.minor))
902 goto out; 882 goto out;
903 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 883 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
904 goto out; 884 tomoyo_same_path_number3_acl,
905 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 885 tomoyo_merge_path_number3_acl);
906 struct tomoyo_path_number3_acl *acl =
907 container_of(ptr, struct tomoyo_path_number3_acl, head);
908 if (!tomoyo_is_same_path_number3_acl(acl, &e))
909 continue;
910 if (is_delete)
911 acl->perm &= ~perm;
912 else
913 acl->perm |= perm;
914 error = 0;
915 break;
916 }
917 if (!is_delete && error) {
918 struct tomoyo_path_number3_acl *entry =
919 tomoyo_commit_ok(&e, sizeof(e));
920 if (entry) {
921 list_add_tail_rcu(&entry->head.list,
922 &domain->acl_info_list);
923 error = 0;
924 }
925 }
926 mutex_unlock(&tomoyo_policy_lock);
927 out: 886 out:
928 tomoyo_put_name_union(&e.name); 887 tomoyo_put_name_union(&e.name);
929 tomoyo_put_number_union(&e.mode); 888 tomoyo_put_number_union(&e.mode);
@@ -932,6 +891,32 @@ static inline int tomoyo_update_path_number3_acl(const u8 type,
932 return error; 891 return error;
933} 892}
934 893
894static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
895 const struct tomoyo_acl_info *b)
896{
897 const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
898 const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
899 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
900 && tomoyo_is_same_name_union(&p1->name1, &p2->name1)
901 && tomoyo_is_same_name_union(&p1->name2, &p2->name2);
902}
903
904static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
905 struct tomoyo_acl_info *b,
906 const bool is_delete)
907{
908 u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
909 ->perm;
910 u8 perm = *a_perm;
911 const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
912 if (is_delete)
913 perm &= ~b_perm;
914 else
915 perm |= b_perm;
916 *a_perm = perm;
917 return !perm;
918}
919
935/** 920/**
936 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 921 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
937 * 922 *
@@ -947,46 +932,20 @@ static inline int tomoyo_update_path_number3_acl(const u8 type,
947 */ 932 */
948static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 933static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
949 const char *filename2, 934 const char *filename2,
950 struct tomoyo_domain_info *const domain, 935 struct tomoyo_domain_info * const domain,
951 const bool is_delete) 936 const bool is_delete)
952{ 937{
953 const u8 perm = 1 << type;
954 struct tomoyo_path2_acl e = { 938 struct tomoyo_path2_acl e = {
955 .head.type = TOMOYO_TYPE_PATH2_ACL, 939 .head.type = TOMOYO_TYPE_PATH2_ACL,
956 .perm = perm 940 .perm = 1 << type
957 }; 941 };
958 struct tomoyo_acl_info *ptr;
959 int error = is_delete ? -ENOENT : -ENOMEM; 942 int error = is_delete ? -ENOENT : -ENOMEM;
960
961 if (!domain)
962 return -EINVAL;
963 if (!tomoyo_parse_name_union(filename1, &e.name1) || 943 if (!tomoyo_parse_name_union(filename1, &e.name1) ||
964 !tomoyo_parse_name_union(filename2, &e.name2)) 944 !tomoyo_parse_name_union(filename2, &e.name2))
965 goto out; 945 goto out;
966 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 946 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
967 goto out; 947 tomoyo_same_path2_acl,
968 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 948 tomoyo_merge_path2_acl);
969 struct tomoyo_path2_acl *acl =
970 container_of(ptr, struct tomoyo_path2_acl, head);
971 if (!tomoyo_is_same_path2_acl(acl, &e))
972 continue;
973 if (is_delete)
974 acl->perm &= ~perm;
975 else
976 acl->perm |= perm;
977 error = 0;
978 break;
979 }
980 if (!is_delete && error) {
981 struct tomoyo_path2_acl *entry =
982 tomoyo_commit_ok(&e, sizeof(e));
983 if (entry) {
984 list_add_tail_rcu(&entry->head.list,
985 &domain->acl_info_list);
986 error = 0;
987 }
988 }
989 mutex_unlock(&tomoyo_policy_lock);
990 out: 949 out:
991 tomoyo_put_name_union(&e.name1); 950 tomoyo_put_name_union(&e.name1);
992 tomoyo_put_name_union(&e.name2); 951 tomoyo_put_name_union(&e.name2);
@@ -1157,6 +1116,35 @@ static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
1157 return error; 1116 return error;
1158} 1117}
1159 1118
1119static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
1120 const struct tomoyo_acl_info *b)
1121{
1122 const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
1123 head);
1124 const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
1125 head);
1126 return tomoyo_is_same_acl_head(&p1->head, &p2->head)
1127 && tomoyo_is_same_name_union(&p1->name, &p2->name)
1128 && tomoyo_is_same_number_union(&p1->number, &p2->number);
1129}
1130
1131static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
1132 struct tomoyo_acl_info *b,
1133 const bool is_delete)
1134{
1135 u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
1136 head)->perm;
1137 u8 perm = *a_perm;
1138 const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
1139 ->perm;
1140 if (is_delete)
1141 perm &= ~b_perm;
1142 else
1143 perm |= b_perm;
1144 *a_perm = perm;
1145 return !perm;
1146}
1147
1160/** 1148/**
1161 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 1149 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
1162 * 1150 *
@@ -1168,50 +1156,24 @@ static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
1168 * 1156 *
1169 * Returns 0 on success, negative value otherwise. 1157 * Returns 0 on success, negative value otherwise.
1170 */ 1158 */
1171static inline int tomoyo_update_path_number_acl(const u8 type, 1159static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
1172 const char *filename, 1160 char *number,
1173 char *number, 1161 struct tomoyo_domain_info * const
1174 struct tomoyo_domain_info * 1162 domain,
1175 const domain, 1163 const bool is_delete)
1176 const bool is_delete)
1177{ 1164{
1178 const u8 perm = 1 << type;
1179 struct tomoyo_acl_info *ptr;
1180 struct tomoyo_path_number_acl e = { 1165 struct tomoyo_path_number_acl e = {
1181 .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 1166 .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
1182 .perm = perm 1167 .perm = 1 << type
1183 }; 1168 };
1184 int error = is_delete ? -ENOENT : -ENOMEM; 1169 int error = is_delete ? -ENOENT : -ENOMEM;
1185 if (!domain)
1186 return -EINVAL;
1187 if (!tomoyo_parse_name_union(filename, &e.name)) 1170 if (!tomoyo_parse_name_union(filename, &e.name))
1188 return -EINVAL; 1171 return -EINVAL;
1189 if (!tomoyo_parse_number_union(number, &e.number)) 1172 if (!tomoyo_parse_number_union(number, &e.number))
1190 goto out; 1173 goto out;
1191 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 1174 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
1192 goto out; 1175 tomoyo_same_path_number_acl,
1193 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 1176 tomoyo_merge_path_number_acl);
1194 struct tomoyo_path_number_acl *acl =
1195 container_of(ptr, struct tomoyo_path_number_acl, head);
1196 if (!tomoyo_is_same_path_number_acl(acl, &e))
1197 continue;
1198 if (is_delete)
1199 acl->perm &= ~perm;
1200 else
1201 acl->perm |= perm;
1202 error = 0;
1203 break;
1204 }
1205 if (!is_delete && error) {
1206 struct tomoyo_path_number_acl *entry =
1207 tomoyo_commit_ok(&e, sizeof(e));
1208 if (entry) {
1209 list_add_tail_rcu(&entry->head.list,
1210 &domain->acl_info_list);
1211 error = 0;
1212 }
1213 }
1214 mutex_unlock(&tomoyo_policy_lock);
1215 out: 1177 out:
1216 tomoyo_put_name_union(&e.name); 1178 tomoyo_put_name_union(&e.name);
1217 tomoyo_put_number_union(&e.number); 1179 tomoyo_put_number_union(&e.number);
@@ -1585,13 +1547,8 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
1585 u8 type; 1547 u8 type;
1586 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1548 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
1587 return -EINVAL; 1549 return -EINVAL;
1588 if (strncmp(w[0], "allow_", 6)) { 1550 if (strncmp(w[0], "allow_", 6))
1589 unsigned int perm;
1590 if (sscanf(w[0], "%u", &perm) == 1)
1591 return tomoyo_update_file_acl((u8) perm, w[1], domain,
1592 is_delete);
1593 goto out; 1551 goto out;
1594 }
1595 w[0] += 6; 1552 w[0] += 6;
1596 for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1553 for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
1597 if (strcmp(w[0], tomoyo_path_keyword[type])) 1554 if (strcmp(w[0], tomoyo_path_keyword[type]))