diff options
author | John Johansen <john.johansen@canonical.com> | 2017-06-09 17:16:46 +0300 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-11 03:11:35 +0300 |
commit | 435222bc1bcc11636f4159fd3ce9e481ab7f2c7c (patch) | |
tree | 3784793c52ecc5a871ea9656df6314b3a13ee587 /security/apparmor/policy.c | |
parent | a1bd627b46d169268a0ee5960899fb5be960a317 (diff) | |
download | linux-435222bc1bcc11636f4159fd3ce9e481ab7f2c7c.tar.xz |
apparmor: refactor updating profiles to the newest parent
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/policy.c')
-rw-r--r-- | security/apparmor/policy.c | 35 |
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); |