summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2023-10-27 10:31:06 -0700
committerJohn Johansen <john.johansen@canonical.com>2025-01-18 06:47:12 -0800
commitde4754c801f4ceefc6ce0d13480c506e0a91b449 (patch)
treebb89e754c051b6d2991df843bbd5b165fffa9c1c
parent34d31f23385b018890295414acaee31d786cf73d (diff)
apparmor: carry mediation check on label
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>
-rw-r--r--security/apparmor/include/apparmor.h1
-rw-r--r--security/apparmor/include/label.h24
-rw-r--r--security/apparmor/include/policy.h13
-rw-r--r--security/apparmor/label.c24
-rw-r--r--security/apparmor/policy.c28
-rw-r--r--security/apparmor/policy_unpack.c2
6 files changed, 68 insertions, 24 deletions
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 56767b1a8f06..dd12cba8139d 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -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 */
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 93290ae300bb..5e7d199c15e2 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -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);
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 757e3c232c57..256fb27e5c3a 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -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)
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 868874ef3d35..afded9996f61 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -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);
}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 25cb34e43786..2857e771e2a9 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -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);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 992b74c50d64..287e08ac4b4b 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -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: