]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
apparmor: carry mediation check on label
authorJohn Johansen <john.johansen@canonical.com>
Fri, 27 Oct 2023 17:31:06 +0000 (10:31 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Sat, 18 Jan 2025 14:47:12 +0000 (06:47 -0800)
In order to speed up the mediated check, precompute and store the
result as a bit per class type. This will not only allow us to
speed up the mediation check but is also a step to removing the
unconfined special cases as the unconfined check can be replaced
with the generic label_mediates() check.

Note: label check does not currently work for capabilities and resources
      which need to have their mediation updated first.

Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/include/apparmor.h
security/apparmor/include/label.h
security/apparmor/include/policy.h
security/apparmor/label.c
security/apparmor/policy.c
security/apparmor/policy_unpack.c

index 56767b1a8f06646dfe28da2ccb248b54441b8dcd..dd12cba8139d4f3ca1c325c4ebc510dcfe1fa17b 100644 (file)
@@ -38,6 +38,7 @@
 #define AA_CLASS_X             31
 #define AA_CLASS_DBUS          32
 
+/* NOTE: if AA_CLASS_LAST > 63 need to update label->mediates */
 #define AA_CLASS_LAST          AA_CLASS_DBUS
 
 /* Control parameters settable through module/boot flags */
index 93290ae300bb2e4dc4acd64e64c083f9130565cd..5e7d199c15e221de68503aaf1e1a84f8cf8c7c8c 100644 (file)
@@ -129,6 +129,7 @@ struct aa_label {
        long flags;
        u32 secid;
        int size;
+       u64 mediates;
        struct aa_profile *vec[];
 };
 
@@ -231,20 +232,17 @@ int aa_label_next_confined(struct aa_label *l, int i);
 #define fn_for_each_not_in_set(L1, L2, P, FN)                          \
        fn_for_each2_XXX((L1), (L2), P, FN, _not_in_set)
 
-#define LABEL_MEDIATES(L, C)                                           \
-({                                                                     \
-       struct aa_profile *profile;                                     \
-       struct label_it i;                                              \
-       int ret = 0;                                                    \
-       label_for_each(i, (L), profile) {                               \
-               if (RULE_MEDIATES(&profile->rules, (C))) {              \
-                       ret = 1;                                        \
-                       break;                                          \
-               }                                                       \
-       }                                                               \
-       ret;                                                            \
-})
+static inline bool label_mediates(struct aa_label *L, unsigned char C)
+{
+       return (L)->mediates & (((u64) 1) << (C));
+}
 
+static inline bool label_mediates_safe(struct aa_label *L, unsigned char C)
+{
+       if (C > AA_CLASS_LAST)
+               return false;
+       return label_mediates(L, C);
+}
 
 void aa_labelset_destroy(struct aa_labelset *ls);
 void aa_labelset_init(struct aa_labelset *ls);
index 757e3c232c571697d0abc68933d6adf124963ef6..256fb27e5c3af424480d6b921901267d597e5303 100644 (file)
@@ -318,6 +318,19 @@ static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head,
        return RULE_MEDIATES(rule, class);
 }
 
+void aa_compute_profile_mediates(struct aa_profile *profile);
+static inline bool profile_mediates(struct aa_profile *profile,
+                                   unsigned char class)
+{
+       return label_mediates(&profile->label, class);
+}
+
+static inline bool profile_mediates_safe(struct aa_profile *profile,
+                                        unsigned char class)
+{
+       return label_mediates_safe(&profile->label, class);
+}
+
 /**
  * aa_get_profile - increment refcount on profile @p
  * @p: profile  (MAYBE NULL)
index 868874ef3d355b9cf5092cff46d5eef58413015c..afded9996f61684b336b4f3a442e66d3a2a32862 100644 (file)
@@ -198,21 +198,25 @@ static bool vec_is_stale(struct aa_profile **vec, int n)
        return false;
 }
 
-static long accum_vec_flags(struct aa_profile **vec, int n)
+static void accum_label_info(struct aa_label *new)
 {
        long u = FLAG_UNCONFINED;
        int i;
 
-       AA_BUG(!vec);
+       AA_BUG(!new->vec);
 
-       for (i = 0; i < n; i++) {
-               u |= vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 |
-                                           FLAG_STALE);
-               if (!(u & vec[i]->label.flags & FLAG_UNCONFINED))
+       /* size == 1 is a profile and flags must be set as part of creation */
+       if (new->size == 1)
+               return;
+
+       for (i = 0; i < new->size; i++) {
+               u |= new->vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 |
+                                                FLAG_STALE);
+               if (!(u & new->vec[i]->label.flags & FLAG_UNCONFINED))
                        u &= ~FLAG_UNCONFINED;
+               new->mediates |= new->vec[i]->label.mediates;
        }
-
-       return u;
+       new->flags |= u;
 }
 
 static int sort_cmp(const void *a, const void *b)
@@ -645,7 +649,7 @@ static bool __label_replace(struct aa_label *old, struct aa_label *new)
                rb_replace_node(&old->node, &new->node, &ls->root);
                old->flags &= ~FLAG_IN_TREE;
                new->flags |= FLAG_IN_TREE;
-               new->flags |= accum_vec_flags(new->vec, new->size);
+               accum_label_info(new);
                return true;
        }
 
@@ -706,7 +710,7 @@ static struct aa_label *__label_insert(struct aa_labelset *ls,
        rb_link_node(&label->node, parent, new);
        rb_insert_color(&label->node, &ls->root);
        label->flags |= FLAG_IN_TREE;
-       label->flags |= accum_vec_flags(label->vec, label->size);
+       accum_label_info(label);
 
        return aa_get_label(label);
 }
index 25cb34e43786917747c57bdc6fca899d15840711..2857e771e2a93d1e616a90045aeb99c655a6091e 100644 (file)
@@ -373,6 +373,30 @@ fail:
        return NULL;
 }
 
+/* set of rules that are mediated by unconfined */
+static int unconfined_mediates[] = { AA_CLASS_NS, AA_CLASS_IO_URING, 0 };
+
+/* must be called after profile rulesets and start information is setup */
+void aa_compute_profile_mediates(struct aa_profile *profile)
+{
+       int c;
+
+       if (profile_unconfined(profile)) {
+               int *pos;
+
+               for (pos = unconfined_mediates; *pos; pos++) {
+                       if (ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_NS) !=
+                           DFA_NOMATCH)
+                               profile->label.mediates |= ((u64) 1) << AA_CLASS_NS;
+               }
+               return;
+       }
+       for (c = 0; c <= AA_CLASS_LAST; c++) {
+               if (ANY_RULE_MEDIATES(&profile->rules, c) != DFA_NOMATCH)
+                       profile->label.mediates |= ((u64) 1) << c;
+       }
+}
+
 /* TODO: profile accounting - setup in remove */
 
 /**
@@ -624,10 +648,12 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
        rules = list_first_entry(&profile->rules, typeof(*rules), list);
        rules->file = aa_get_pdb(nullpdb);
        rules->policy = aa_get_pdb(nullpdb);
+       aa_compute_profile_mediates(profile);
 
        if (parent) {
                profile->path_flags = parent->path_flags;
-
+               /* override/inherit what is mediated from parent */
+               profile->label.mediates = parent->label.mediates;
                /* released on free_profile */
                rcu_assign_pointer(profile->parent, aa_get_profile(parent));
                profile->ns = aa_get_ns(parent->ns);
index 992b74c50d641e697138a640bb19b14620d51c2b..287e08ac4b4b55f866a7c128da9a68643f78507b 100644 (file)
@@ -1101,6 +1101,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                goto fail;
        }
 
+       aa_compute_profile_mediates(profile);
+
        return profile;
 
 fail: