apparmor: add a conditional version of get_newest_label

get_newest_label() will always return a refcount, on the profile it
returns. However there are cases where we only need the refcount
if the label is stale and get_newest_label() will return a different
label.

Optimize this by making the get/put happen conditionally, by keeping
a flag indicating if the get was performed and a put is needed.

Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2026-04-17 00:51:22 -07:00
parent 6d25e7b476
commit f86ee868fd
2 changed files with 43 additions and 11 deletions

View File

@ -423,6 +423,38 @@ static inline struct aa_label *aa_get_newest_label(struct aa_label *l)
return aa_get_label(l);
}
/**
* aa_get_newest_label_condref - find the newest version of @l
* @l: the label to check for newer versions of
* @needput: returns whether the reference needs put
*
* Returns: refcounted newest version of @l taking into account
* replacement, renames and removals
* return @l.
*/
static inline struct aa_label *aa_get_newest_label_condref(struct aa_label *l,
bool *needput)
{
if (l && unlikely(label_is_stale(l))) {
struct aa_label *tmp;
AA_BUG(!l->proxy);
AA_BUG(!l->proxy->label);
/* BUG: only way this can happen is @l ref count and its
* replacement count have gone to 0 and are on their way
* to destruction. ie. we have a refcounting error
*/
tmp = aa_get_label_rcu(&l->proxy->label);
AA_BUG(!tmp);
*needput = true;
return tmp;
}
*needput = false;
return l;
}
static inline void aa_put_label(struct aa_label *l)
{
if (l)

View File

@ -1176,22 +1176,21 @@ static struct aa_label *__label_find_merge(struct aa_labelset *ls,
struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b)
{
struct aa_labelset *ls;
struct aa_label *label, *ar = NULL, *br = NULL;
struct aa_label *label;
unsigned long flags;
bool a_needput, b_needput;
AA_BUG(!a);
AA_BUG(!b);
if (label_is_stale(a))
a = ar = aa_get_newest_label(a);
if (label_is_stale(b))
b = br = aa_get_newest_label(b);
a = aa_get_newest_label_condref(a, &a_needput);
b = aa_get_newest_label_condref(b, &b_needput);
ls = labelset_of_merge(a, b);
read_lock_irqsave(&ls->lock, flags);
label = __label_find_merge(ls, a, b);
read_unlock_irqrestore(&ls->lock, flags);
aa_put_label(ar);
aa_put_label(br);
aa_put_label_condref(a, a_needput);
aa_put_label_condref(b, b_needput);
return label;
}
@ -1228,9 +1227,10 @@ struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b,
if (!label) {
struct aa_label *new;
bool a_needput, b_needput;
a = aa_get_newest_label(a);
b = aa_get_newest_label(b);
a = aa_get_newest_label_condref(a, &a_needput);
b = aa_get_newest_label_condref(b, &b_needput);
/* could use label_merge_len(a, b), but requires double
* comparison for small savings
@ -1242,8 +1242,8 @@ struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b,
label = label_merge_insert(new, a, b);
label_free_or_put_new(label, new);
out:
aa_put_label(a);
aa_put_label(b);
aa_put_label_condref(a, a_needput);
aa_put_label_condref(b, b_needput);
}
return label;