Commit 7a1cf8a9 authored by John Johansen's avatar John Johansen Committed by Tim Gardner

UBUNTU: SAUCE: apparmor: Fix: deadlock in aa_put_label() call chain

BugLink: http://bugs.launchpad.net/bugs/1448912

When aa_put_label() is called from a fn that is holding the labelset
lock, it can result in a deadlock if the put count reaches 0 triggering
the kref callback, which tries to take the label set lock.

Rework so the label_kref callback deferrs removing the label from
the labelset until the rcu callback, ensuring the lock is not held
by the calling code.
Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
parent 62a5fac9
......@@ -234,10 +234,8 @@ void aa_label_free(struct aa_label *label)
kfree(label);
}
static void label_free_rcu(struct rcu_head *head)
static void label_free_switch(struct aa_label *l)
{
struct aa_label *l = container_of(head, struct aa_label, rcu);
if (l->flags & FLAG_NS_COUNT)
aa_free_namespace(labels_ns(l));
else if (label_isprofile(l))
......@@ -246,6 +244,14 @@ static void label_free_rcu(struct rcu_head *head)
aa_label_free(l);
}
static void label_free_rcu(struct rcu_head *head)
{
struct aa_label *l = container_of(head, struct aa_label, rcu);
(void) aa_label_remove(labels_set(l), l);
label_free_switch(l);
}
bool aa_label_remove(struct aa_labelset *ls, struct aa_label *label);
void aa_label_kref(struct kref *kref)
{
......@@ -254,12 +260,10 @@ void aa_label_kref(struct kref *kref)
if (!ns) {
/* never live, no rcu callback needed, just using the fn */
label_free_rcu(&l->rcu);
label_free_switch(l);
return;
}
(void) aa_label_remove(&ns->labels, l);
/* TODO: if compound label and not invalid add to reclaim cache */
call_rcu(&l->rcu, label_free_rcu);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment