summaryrefslogtreecommitdiff
path: root/security/apparmor/policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/policy.c')
-rw-r--r--security/apparmor/policy.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index ff29b606f2b3..eb1ccd171789 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -819,7 +819,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace,
struct aa_ns *ns = NULL;
struct aa_load_ent *ent, *tmp;
int op = OP_PROF_REPL;
- ssize_t error;
+ ssize_t count, error;
LIST_HEAD(lh);
/* released below */
@@ -827,14 +827,40 @@ ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace,
if (error)
goto out;
- /* released below */
- ns = aa_prepare_ns(view, ns_name);
- if (!ns) {
- error = audit_policy(__aa_current_profile(), op, GFP_KERNEL,
- NULL, ns_name,
- "failed to prepare namespace", -ENOMEM);
- goto free;
+ /* ensure that profiles are all for the same ns
+ * TODO: update locking to remove this constaint. All profiles in
+ * the load set must succeed as a set or the load will
+ * fail. Sort ent list and take ns locks in hierarchy order
+ */
+ count = 0;
+ list_for_each_entry(ent, &lh, list) {
+ if (ns_name) {
+ if (ent->ns_name &&
+ strcmp(ent->ns_name, ns_name) != 0) {
+ info = "policy load has mixed namespaces";
+ error = -EACCES;
+ goto fail;
+ }
+ } else if (ent->ns_name) {
+ if (count) {
+ info = "policy load has mixed namespaces";
+ error = -EACCES;
+ goto fail;
+ }
+ ns_name = ent->ns_name;
+ } else
+ count++;
}
+ if (ns_name) {
+ ns = aa_prepare_ns(view, ns_name);
+ if (IS_ERR(ns)) {
+ info = "failed to prepare namespace";
+ error = PTR_ERR(ns);
+ ns = NULL;
+ goto fail;
+ }
+ } else
+ ns = aa_get_ns(view);
mutex_lock(&ns->lock);
/* setup parent and ns info */
@@ -964,7 +990,8 @@ fail_lock:
/* audit cause of failure */
op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
- audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL,
+fail:
+ audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name,
ent->new->base.hname, info, error);
/* audit status that rest of profiles in the atomic set failed too */
info = "valid profile in failed atomic policy load";
@@ -975,10 +1002,9 @@ fail_lock:
continue;
}
op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
- audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL,
+ audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name,
tmp->new->base.hname, info, error);
}
-free:
list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list);
aa_load_ent_free(ent);
@@ -1005,6 +1031,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size)
struct aa_ns *root = NULL, *ns = NULL;
struct aa_profile *profile = NULL;
const char *name = fqname, *info = NULL;
+ char *ns_name = NULL;
ssize_t error = 0;
if (*fqname == 0) {
@@ -1016,7 +1043,6 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size)
root = view;
if (fqname[0] == ':') {
- char *ns_name;
name = aa_split_fqname(fqname, &ns_name);
/* released below */
ns = aa_find_ns(root, ns_name);
@@ -1050,7 +1076,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size)
/* don't fail removal if audit fails */
(void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL,
- NULL, name, info, error);
+ ns_name, name, info, error);
aa_put_ns(ns);
aa_put_profile(profile);
return size;
@@ -1061,6 +1087,6 @@ fail_ns_lock:
fail:
(void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL,
- NULL, name, info, error);
+ ns_name, name, info, error);
return error;
}