aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/apparmor/apparmorfs.c1
-rw-r--r--security/apparmor/include/policy_unpack.h14
-rw-r--r--security/apparmor/policy.c300
-rw-r--r--security/apparmor/policy_unpack.c114
4 files changed, 283 insertions, 146 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index ad6c74892b5f..3ed56e21a9fd 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -199,6 +199,7 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
199}; 199};
200 200
201static struct aa_fs_entry aa_fs_entry_policy[] = { 201static struct aa_fs_entry aa_fs_entry_policy[] = {
202 AA_FS_FILE_BOOLEAN("set_load", 1),
202 {} 203 {}
203}; 204};
204 205
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
index a2dcccac45aa..0d7ad722b8ff 100644
--- a/security/apparmor/include/policy_unpack.h
+++ b/security/apparmor/include/policy_unpack.h
@@ -15,6 +15,18 @@
15#ifndef __POLICY_INTERFACE_H 15#ifndef __POLICY_INTERFACE_H
16#define __POLICY_INTERFACE_H 16#define __POLICY_INTERFACE_H
17 17
18struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns); 18#include <linux/list.h>
19
20struct aa_load_ent {
21 struct list_head list;
22 struct aa_profile *new;
23 struct aa_profile *old;
24 struct aa_profile *rename;
25};
26
27void aa_load_ent_free(struct aa_load_ent *ent);
28struct aa_load_ent *aa_load_ent_alloc(void);
29
30int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns);
19 31
20#endif /* __POLICY_INTERFACE_H */ 32#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 0f345c4dee5f..407b442c0a2c 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -472,45 +472,6 @@ static void __list_remove_profile(struct aa_profile *profile)
472 aa_put_profile(profile); 472 aa_put_profile(profile);
473} 473}
474 474
475/**
476 * __replace_profile - replace @old with @new on a list
477 * @old: profile to be replaced (NOT NULL)
478 * @new: profile to replace @old with (NOT NULL)
479 *
480 * Will duplicate and refcount elements that @new inherits from @old
481 * and will inherit @old children.
482 *
483 * refcount @new for list, put @old list refcount
484 *
485 * Requires: namespace list lock be held, or list not be shared
486 */
487static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
488{
489 struct aa_policy *policy;
490 struct aa_profile *child, *tmp;
491
492 if (old->parent)
493 policy = &old->parent->base;
494 else
495 policy = &old->ns->base;
496
497 /* released when @new is freed */
498 new->parent = aa_get_profile(old->parent);
499 new->ns = aa_get_namespace(old->ns);
500 __list_add_profile(&policy->profiles, new);
501 /* inherit children */
502 list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
503 aa_put_profile(child->parent);
504 child->parent = aa_get_profile(new);
505 /* list refcount transferred to @new*/
506 list_move(&child->base.list, &new->base.profiles);
507 }
508
509 /* released by free_profile */
510 old->replacedby = aa_get_profile(new);
511 __list_remove_profile(old);
512}
513
514static void __profile_list_release(struct list_head *head); 475static void __profile_list_release(struct list_head *head);
515 476
516/** 477/**
@@ -953,25 +914,6 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
953} 914}
954 915
955/** 916/**
956 * __add_new_profile - simple wrapper around __list_add_profile
957 * @ns: namespace that profile is being added to (NOT NULL)
958 * @policy: the policy container to add the profile to (NOT NULL)
959 * @profile: profile to add (NOT NULL)
960 *
961 * add a profile to a list and do other required basic allocations
962 */
963static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
964 struct aa_profile *profile)
965{
966 if (policy != &ns->base)
967 /* released on profile replacement or free_profile */
968 profile->parent = aa_get_profile((struct aa_profile *) policy);
969 __list_add_profile(&policy->profiles, profile);
970 /* released on free_profile */
971 profile->ns = aa_get_namespace(ns);
972}
973
974/**
975 * aa_audit_policy - Do auditing of policy changes 917 * aa_audit_policy - Do auditing of policy changes
976 * @op: policy operation being performed 918 * @op: policy operation being performed
977 * @gfp: memory allocation flags 919 * @gfp: memory allocation flags
@@ -1019,6 +961,109 @@ bool aa_may_manage_policy(int op)
1019 return 1; 961 return 1;
1020} 962}
1021 963
964static struct aa_profile *__list_lookup_parent(struct list_head *lh,
965 struct aa_profile *profile)
966{
967 const char *base = hname_tail(profile->base.hname);
968 long len = base - profile->base.hname;
969 struct aa_load_ent *ent;
970
971 /* parent won't have trailing // so remove from len */
972 if (len <= 2)
973 return NULL;
974 len -= 2;
975
976 list_for_each_entry(ent, lh, list) {
977 if (ent->new == profile)
978 continue;
979 if (strncmp(ent->new->base.hname, profile->base.hname, len) ==
980 0 && ent->new->base.hname[len] == 0)
981 return ent->new;
982 }
983
984 return NULL;
985}
986
987/**
988 * __replace_profile - replace @old with @new on a list
989 * @old: profile to be replaced (NOT NULL)
990 * @new: profile to replace @old with (NOT NULL)
991 *
992 * Will duplicate and refcount elements that @new inherits from @old
993 * and will inherit @old children.
994 *
995 * refcount @new for list, put @old list refcount
996 *
997 * Requires: namespace list lock be held, or list not be shared
998 */
999static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
1000{
1001 struct aa_profile *child, *tmp;
1002
1003 if (!list_empty(&old->base.profiles)) {
1004 LIST_HEAD(lh);
1005 list_splice_init(&old->base.profiles, &lh);
1006
1007 list_for_each_entry_safe(child, tmp, &lh, base.list) {
1008 struct aa_profile *p;
1009
1010 list_del_init(&child->base.list);
1011 p = __find_child(&new->base.profiles, child->base.name);
1012 if (p) {
1013 /* @p replaces @child */
1014 __replace_profile(child, p);
1015 continue;
1016 }
1017
1018 /* inherit @child and its children */
1019 /* TODO: update hname of inherited children */
1020 /* list refcount transferred to @new */
1021 list_add(&child->base.list, &new->base.profiles);
1022 aa_put_profile(child->parent);
1023 child->parent = aa_get_profile(new);
1024 }
1025 }
1026
1027 if (!new->parent)
1028 new->parent = aa_get_profile(old->parent);
1029 /* released by free_profile */
1030 old->replacedby = aa_get_profile(new);
1031
1032 if (list_empty(&new->base.list)) {
1033 /* new is not on a list already */
1034 list_replace_init(&old->base.list, &new->base.list);
1035 aa_get_profile(new);
1036 aa_put_profile(old);
1037 } else
1038 __list_remove_profile(old);
1039}
1040
1041/**
1042 * __lookup_replace - lookup replacement information for a profile
1043 * @ns - namespace the lookup occurs in
1044 * @hname - name of profile to lookup
1045 * @noreplace - true if not replacing an existing profile
1046 * @p - Returns: profile to be replaced
1047 * @info - Returns: info string on why lookup failed
1048 *
1049 * Returns: profile to replace (no ref) on success else ptr error
1050 */
1051static int __lookup_replace(struct aa_namespace *ns, const char *hname,
1052 bool noreplace, struct aa_profile **p,
1053 const char **info)
1054{
1055 *p = aa_get_profile(__lookup_profile(&ns->base, hname));
1056 if (*p) {
1057 int error = replacement_allowed(*p, noreplace, info);
1058 if (error) {
1059 *info = "profile can not be replaced";
1060 return error;
1061 }
1062 }
1063
1064 return 0;
1065}
1066
1022/** 1067/**
1023 * aa_replace_profiles - replace profile(s) on the profile list 1068 * aa_replace_profiles - replace profile(s) on the profile list
1024 * @udata: serialized data stream (NOT NULL) 1069 * @udata: serialized data stream (NOT NULL)
@@ -1033,21 +1078,17 @@ bool aa_may_manage_policy(int op)
1033 */ 1078 */
1034ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) 1079ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
1035{ 1080{
1036 struct aa_policy *policy;
1037 struct aa_profile *old_profile = NULL, *new_profile = NULL;
1038 struct aa_profile *rename_profile = NULL;
1039 struct aa_namespace *ns = NULL;
1040 const char *ns_name, *name = NULL, *info = NULL; 1081 const char *ns_name, *name = NULL, *info = NULL;
1082 struct aa_namespace *ns = NULL;
1083 struct aa_load_ent *ent, *tmp;
1041 int op = OP_PROF_REPL; 1084 int op = OP_PROF_REPL;
1042 ssize_t error; 1085 ssize_t error;
1086 LIST_HEAD(lh);
1043 1087
1044 /* released below */ 1088 /* released below */
1045 new_profile = aa_unpack(udata, size, &ns_name); 1089 error = aa_unpack(udata, size, &lh, &ns_name);
1046 if (IS_ERR(new_profile)) { 1090 if (error)
1047 error = PTR_ERR(new_profile); 1091 goto out;
1048 new_profile = NULL;
1049 goto fail;
1050 }
1051 1092
1052 /* released below */ 1093 /* released below */
1053 ns = aa_prepare_namespace(ns_name); 1094 ns = aa_prepare_namespace(ns_name);
@@ -1058,71 +1099,96 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
1058 goto fail; 1099 goto fail;
1059 } 1100 }
1060 1101
1061 name = new_profile->base.hname;
1062
1063 write_lock(&ns->lock); 1102 write_lock(&ns->lock);
1064 /* no ref on policy only use inside lock */ 1103 /* setup parent and ns info */
1065 policy = __lookup_parent(ns, new_profile->base.hname); 1104 list_for_each_entry(ent, &lh, list) {
1066 1105 struct aa_policy *policy;
1067 if (!policy) { 1106
1068 info = "parent does not exist"; 1107 name = ent->new->base.hname;
1069 error = -ENOENT; 1108 error = __lookup_replace(ns, ent->new->base.hname, noreplace,
1070 goto audit; 1109 &ent->old, &info);
1071 } 1110 if (error)
1072 1111 goto fail_lock;
1073 old_profile = __find_child(&policy->profiles, new_profile->base.name); 1112
1074 /* released below */ 1113 if (ent->new->rename) {
1075 aa_get_profile(old_profile); 1114 error = __lookup_replace(ns, ent->new->rename,
1076 1115 noreplace, &ent->rename,
1077 if (new_profile->rename) { 1116 &info);
1078 rename_profile = __lookup_profile(&ns->base, 1117 if (error)
1079 new_profile->rename); 1118 goto fail_lock;
1080 /* released below */
1081 aa_get_profile(rename_profile);
1082
1083 if (!rename_profile) {
1084 info = "profile to rename does not exist";
1085 name = new_profile->rename;
1086 error = -ENOENT;
1087 goto audit;
1088 } 1119 }
1089 }
1090
1091 error = replacement_allowed(old_profile, noreplace, &info);
1092 if (error)
1093 goto audit;
1094 1120
1095 error = replacement_allowed(rename_profile, noreplace, &info); 1121 /* released when @new is freed */
1096 if (error) 1122 ent->new->ns = aa_get_namespace(ns);
1097 goto audit; 1123
1098 1124 if (ent->old || ent->rename)
1099audit: 1125 continue;
1100 if (!old_profile && !rename_profile) 1126
1101 op = OP_PROF_LOAD; 1127 /* no ref on policy only use inside lock */
1128 policy = __lookup_parent(ns, ent->new->base.hname);
1129 if (!policy) {
1130 struct aa_profile *p;
1131 p = __list_lookup_parent(&lh, ent->new);
1132 if (!p) {
1133 error = -ENOENT;
1134 info = "parent does not exist";
1135 name = ent->new->base.hname;
1136 goto fail_lock;
1137 }
1138 ent->new->parent = aa_get_profile(p);
1139 } else if (policy != &ns->base)
1140 /* released on profile replacement or free_profile */
1141 ent->new->parent = aa_get_profile((struct aa_profile *)
1142 policy);
1143 }
1102 1144
1103 error = audit_policy(op, GFP_ATOMIC, name, info, error); 1145 /* do actual replacement */
1146 list_for_each_entry_safe(ent, tmp, &lh, list) {
1147 list_del_init(&ent->list);
1148 op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
1149
1150 audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error);
1151
1152 if (ent->old) {
1153 __replace_profile(ent->old, ent->new);
1154 if (ent->rename)
1155 __replace_profile(ent->rename, ent->new);
1156 } else if (ent->rename) {
1157 __replace_profile(ent->rename, ent->new);
1158 } else if (ent->new->parent) {
1159 struct aa_profile *parent;
1160 parent = aa_newest_version(ent->new->parent);
1161 /* parent replaced in this atomic set? */
1162 if (parent != ent->new->parent) {
1163 aa_get_profile(parent);
1164 aa_put_profile(ent->new->parent);
1165 ent->new->parent = parent;
1166 }
1167 __list_add_profile(&parent->base.profiles, ent->new);
1168 } else
1169 __list_add_profile(&ns->base.profiles, ent->new);
1104 1170
1105 if (!error) { 1171 aa_load_ent_free(ent);
1106 if (rename_profile)
1107 __replace_profile(rename_profile, new_profile);
1108 if (old_profile)
1109 __replace_profile(old_profile, new_profile);
1110 if (!(old_profile || rename_profile))
1111 __add_new_profile(ns, policy, new_profile);
1112 } 1172 }
1113 write_unlock(&ns->lock); 1173 write_unlock(&ns->lock);
1114 1174
1115out: 1175out:
1116 aa_put_namespace(ns); 1176 aa_put_namespace(ns);
1117 aa_put_profile(rename_profile); 1177
1118 aa_put_profile(old_profile);
1119 aa_put_profile(new_profile);
1120 if (error) 1178 if (error)
1121 return error; 1179 return error;
1122 return size; 1180 return size;
1123 1181
1182fail_lock:
1183 write_unlock(&ns->lock);
1124fail: 1184fail:
1125 error = audit_policy(op, GFP_KERNEL, name, info, error); 1185 error = audit_policy(op, GFP_KERNEL, name, info, error);
1186
1187 list_for_each_entry_safe(ent, tmp, &lh, list) {
1188 list_del_init(&ent->list);
1189 aa_load_ent_free(ent);
1190 }
1191
1126 goto out; 1192 goto out;
1127} 1193}
1128 1194
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 6dac7d77cb4d..080a26b11f01 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -333,8 +333,10 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
333 /* 333 /*
334 * The dfa is aligned with in the blob to 8 bytes 334 * The dfa is aligned with in the blob to 8 bytes
335 * from the beginning of the stream. 335 * from the beginning of the stream.
336 * alignment adjust needed by dfa unpack
336 */ 337 */
337 size_t sz = blob - (char *)e->start; 338 size_t sz = blob - (char *) e->start -
339 ((e->pos - e->start) & 7);
338 size_t pad = ALIGN(sz, 8) - sz; 340 size_t pad = ALIGN(sz, 8) - sz;
339 int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | 341 int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
340 TO_ACCEPT2_FLAG(YYTD_DATA32); 342 TO_ACCEPT2_FLAG(YYTD_DATA32);
@@ -622,29 +624,41 @@ fail:
622/** 624/**
623 * verify_head - unpack serialized stream header 625 * verify_head - unpack serialized stream header
624 * @e: serialized data read head (NOT NULL) 626 * @e: serialized data read head (NOT NULL)
627 * @required: whether the header is required or optional
625 * @ns: Returns - namespace if one is specified else NULL (NOT NULL) 628 * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
626 * 629 *
627 * Returns: error or 0 if header is good 630 * Returns: error or 0 if header is good
628 */ 631 */
629static int verify_header(struct aa_ext *e, const char **ns) 632static int verify_header(struct aa_ext *e, int required, const char **ns)
630{ 633{
631 int error = -EPROTONOSUPPORT; 634 int error = -EPROTONOSUPPORT;
635 const char *name = NULL;
636 *ns = NULL;
637
632 /* get the interface version */ 638 /* get the interface version */
633 if (!unpack_u32(e, &e->version, "version")) { 639 if (!unpack_u32(e, &e->version, "version")) {
634 audit_iface(NULL, NULL, "invalid profile format", e, error); 640 if (required) {
635 return error; 641 audit_iface(NULL, NULL, "invalid profile format", e,
636 } 642 error);
643 return error;
644 }
637 645
638 /* check that the interface version is currently supported */ 646 /* check that the interface version is currently supported */
639 if (e->version != 5) { 647 if (e->version != 5) {
640 audit_iface(NULL, NULL, "unsupported interface version", e, 648 audit_iface(NULL, NULL, "unsupported interface version",
641 error); 649 e, error);
642 return error; 650 return error;
651 }
643 } 652 }
644 653
654
645 /* read the namespace if present */ 655 /* read the namespace if present */
646 if (!unpack_str(e, ns, "namespace")) 656 if (unpack_str(e, &name, "namespace")) {
647 *ns = NULL; 657 if (*ns && strcmp(*ns, name))
658 audit_iface(NULL, NULL, "invalid ns change", e, error);
659 else if (!*ns)
660 *ns = name;
661 }
648 662
649 return 0; 663 return 0;
650} 664}
@@ -693,18 +707,40 @@ static int verify_profile(struct aa_profile *profile)
693 return 0; 707 return 0;
694} 708}
695 709
710void aa_load_ent_free(struct aa_load_ent *ent)
711{
712 if (ent) {
713 aa_put_profile(ent->rename);
714 aa_put_profile(ent->old);
715 aa_put_profile(ent->new);
716 kzfree(ent);
717 }
718}
719
720struct aa_load_ent *aa_load_ent_alloc(void)
721{
722 struct aa_load_ent *ent = kzalloc(sizeof(*ent), GFP_KERNEL);
723 if (ent)
724 INIT_LIST_HEAD(&ent->list);
725 return ent;
726}
727
696/** 728/**
697 * aa_unpack - unpack packed binary profile data loaded from user space 729 * aa_unpack - unpack packed binary profile(s) data loaded from user space
698 * @udata: user data copied to kmem (NOT NULL) 730 * @udata: user data copied to kmem (NOT NULL)
699 * @size: the size of the user data 731 * @size: the size of the user data
732 * @lh: list to place unpacked profiles in a aa_repl_ws
700 * @ns: Returns namespace profile is in if specified else NULL (NOT NULL) 733 * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
701 * 734 *
702 * Unpack user data and return refcounted allocated profile or ERR_PTR 735 * Unpack user data and return refcounted allocated profile(s) stored in
736 * @lh in order of discovery, with the list chain stored in base.list
737 * or error
703 * 738 *
704 * Returns: profile else error pointer if fails to unpack 739 * Returns: profile(s) on @lh else error pointer if fails to unpack
705 */ 740 */
706struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns) 741int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns)
707{ 742{
743 struct aa_load_ent *tmp, *ent;
708 struct aa_profile *profile = NULL; 744 struct aa_profile *profile = NULL;
709 int error; 745 int error;
710 struct aa_ext e = { 746 struct aa_ext e = {
@@ -713,20 +749,42 @@ struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns)
713 .pos = udata, 749 .pos = udata,
714 }; 750 };
715 751
716 error = verify_header(&e, ns); 752 *ns = NULL;
717 if (error) 753 while (e.pos < e.end) {
718 return ERR_PTR(error); 754 error = verify_header(&e, e.pos == e.start, ns);
755 if (error)
756 goto fail;
719 757
720 profile = unpack_profile(&e); 758 profile = unpack_profile(&e);
721 if (IS_ERR(profile)) 759 if (IS_ERR(profile)) {
722 return profile; 760 error = PTR_ERR(profile);
761 goto fail;
762 }
763
764 error = verify_profile(profile);
765 if (error) {
766 aa_put_profile(profile);
767 goto fail;
768 }
769
770 ent = aa_load_ent_alloc();
771 if (!ent) {
772 error = -ENOMEM;
773 aa_put_profile(profile);
774 goto fail;
775 }
723 776
724 error = verify_profile(profile); 777 ent->new = profile;
725 if (error) { 778 list_add_tail(&ent->list, lh);
726 aa_put_profile(profile);
727 profile = ERR_PTR(error);
728 } 779 }
729 780
730 /* return refcount */ 781 return 0;
731 return profile; 782
783fail:
784 list_for_each_entry_safe(ent, tmp, lh, list) {
785 list_del_init(&ent->list);
786 aa_load_ent_free(ent);
787 }
788
789 return error;
732} 790}