aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor/policy.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2013-07-11 00:05:43 -0400
committerJohn Johansen <john.johansen@canonical.com>2013-08-14 14:42:06 -0400
commitdd51c84857630e77c139afe4d9bba65fc051dc3f (patch)
tree2dbfb9435feadac6123600aef75004ee2197f6af /security/apparmor/policy.c
parent9d910a3bc01008d432b3bb79a69e7e3cdb4821b2 (diff)
apparmor: provide base for multiple profiles to be replaced at once
previously profiles had to be loaded one at a time, which could result in cases where a replacement of a set would partially succeed, and then fail resulting in inconsistent policy. Allow multiple profiles to replaced "atomically" so that the replacement either succeeds or fails for the entire set of profiles. Signed-off-by: John Johansen <john.johansen@canonical.com>
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