summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-06-09 16:16:46 +0200
committerJohn Johansen <john.johansen@canonical.com>2017-06-11 02:11:35 +0200
commit435222bc1bcc11636f4159fd3ce9e481ab7f2c7c (patch)
tree3784793c52ecc5a871ea9656df6314b3a13ee587 /security
parentapparmor: share profile name on replacement (diff)
downloadlinux-435222bc1bcc11636f4159fd3ce9e481ab7f2c7c.tar.xz
linux-435222bc1bcc11636f4159fd3ce9e481ab7f2c7c.zip
apparmor: refactor updating profiles to the newest parent
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/policy.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index af925c07ad4e..20613186b1d8 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -837,6 +837,27 @@ static void share_name(struct aa_profile *old, struct aa_profile *new)
new->base.name = old->base.name;
}
+/* Update to newest version of parent after previous replacements
+ * Returns: unrefcount newest version of parent
+ */
+static struct aa_profile *update_to_newest_parent(struct aa_profile *new)
+{
+ struct aa_profile *parent, *newest;
+
+ parent = rcu_dereference_protected(new->parent,
+ mutex_is_locked(&new->ns->lock));
+ newest = aa_get_newest_profile(parent);
+
+ /* parent replaced in this atomic set? */
+ if (newest != parent) {
+ aa_put_profile(parent);
+ rcu_assign_pointer(new->parent, newest);
+ } else
+ aa_put_profile(newest);
+
+ return newest;
+}
+
/**
* aa_replace_profiles - replace profile(s) on the profile list
* @policy_ns: namespace load is occurring on
@@ -1052,10 +1073,16 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_profile *profile,
__list_add_profile(&newest->base.profiles, ent->new);
aa_put_profile(newest);
} else {
- /* aafs interface uses proxy */
- rcu_assign_pointer(ent->new->proxy->profile,
- aa_get_profile(ent->new));
- __list_add_profile(&ns->base.profiles, ent->new);
+ struct list_head *lh;
+
+ if (rcu_access_pointer(ent->new->parent)) {
+ struct aa_profile *parent;
+
+ parent = update_to_newest_parent(ent->new);
+ lh = &parent->base.profiles;
+ } else
+ lh = &ns->base.profiles;
+ __list_add_profile(lh, ent->new);
}
skip:
aa_load_ent_free(ent);