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>
This commit is contained in:
John Johansen 2023-10-27 10:31:06 -07:00
parent 34d31f2338
commit de4754c801
6 changed files with 68 additions and 24 deletions

View 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 */

View 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);

View 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)

View 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);
}

View File

@ -373,6 +373,30 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
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);

View 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: