aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor/policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/policy.c')
-rw-r--r--security/apparmor/policy.c300
1 files changed, 183 insertions, 117 deletions
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