summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2026-04-17 00:51:22 -0700
committerJohn Johansen <john.johansen@canonical.com>2026-06-13 20:14:06 -0700
commitf86ee868fd54c372255519284e1c0f4f7707c045 (patch)
tree40bbe9500a712045a22b9dbeb97f29f98c36061e /security
parent6d25e7b47616cb2db43351210929c8f19dc305a3 (diff)
downloadlinux-next-f86ee868fd54c372255519284e1c0f4f7707c045.tar.gz
linux-next-f86ee868fd54c372255519284e1c0f4f7707c045.zip
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>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/include/label.h32
-rw-r--r--security/apparmor/label.c22
2 files changed, 43 insertions, 11 deletions
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 335f21930702..b5a722a47fd2 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 3a721fdf1833..a8850d118c9c 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;