Commit de4754c8 authored by John Johansen's avatar John Johansen
Browse files

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: default avatarJohn Johansen <john.johansen@canonical.com>
parent 34d31f23
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+11 −13
Original line number Diff line number Diff line
@@ -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);
+13 −0
Original line number Diff line number Diff line
@@ -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)
+14 −10
Original line number Diff line number Diff line
@@ -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 |
	/* 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 & vec[i]->label.flags & FLAG_UNCONFINED))
		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);
}
+27 −1
Original line number Diff line number Diff line
@@ -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);
Loading