From: John Johansen Date: Fri, 17 Apr 2026 07:51:22 +0000 (-0700) Subject: apparmor: add a conditional version of get_newest_label X-Git-Tag: v7.2-rc1~43^2~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f86ee868fd54c372255519284e1c0f4f7707c045;p=thirdparty%2Fkernel%2Flinux.git 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 --- diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 335f21930702a..b5a722a47fd2c 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -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) diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 3a721fdf18339..a8850d118c9cc 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -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;