Commit b5b57993 authored by Mike Salvatore's avatar Mike Salvatore Committed by John Johansen
Browse files

apparmor: compute xmatch permissions on profile load



Rather than computing xmatch permissions each time access is requested,
these permissions can be computed once on profile load and stored for
lookup.

Signed-off-by: default avatarMike Salvatore <mike.salvatore@canonical.com>
Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 408d53e9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -339,7 +339,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
			/* Check xattr value */
			state = aa_dfa_match_len(profile->xmatch, state, value,
						 size);
			perm = dfa_user_allow(profile->xmatch, state);
			perm = profile->xmatch_perms[state];
			if (!(perm & MAY_EXEC)) {
				ret = -EINVAL;
				goto out;
@@ -419,7 +419,7 @@ static struct aa_label *find_attach(const struct linux_binprm *bprm,

			state = aa_dfa_leftmatch(profile->xmatch, DFA_START,
						 name, &count);
			perm = dfa_user_allow(profile->xmatch, state);
			perm = profile->xmatch_perms[state];
			/* any accepting state means a valid match. */
			if (perm & MAY_EXEC) {
				int ret = 0;
+2 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ struct aa_data {
 * @attach: human readable attachment string
 * @xmatch: optional extended matching for unconfined executables names
 * @xmatch_len: xmatch prefix len, used to determine xmatch priority
 * @xmatch_perms: precomputed permissions for the xmatch DFA indexed by state
 * @audit: the auditing mode of the profile
 * @mode: the enforcement mode of the profile
 * @path_flags: flags controlling path generation behavior
@@ -140,6 +141,7 @@ struct aa_profile {
	const char *attach;
	struct aa_dfa *xmatch;
	unsigned int xmatch_len;
	u32 *xmatch_perms;
	enum audit_mode audit;
	long mode;
	u32 path_flags;
+1 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ void aa_free_profile(struct aa_profile *profile)
	kfree_sensitive(profile->secmark);
	kfree_sensitive(profile->dirname);
	aa_put_dfa(profile->xmatch);
	kvfree(profile->xmatch_perms);
	aa_put_dfa(profile->policy.dfa);

	if (profile->data) {
+21 −1
Original line number Diff line number Diff line
@@ -669,6 +669,23 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj)
	return strcmp(data->key, *key);
}

static u32 *aa_compute_xmatch_perms(struct aa_dfa *xmatch)
{
	u32 *perms_table;
	int state;
	int state_count = xmatch->tables[YYTD_ID_BASE]->td_lolen;

	// DFAs are restricted from having a state_count of less than 2
	perms_table = kvcalloc(state_count, sizeof(u32), GFP_KERNEL);

	// Since perms_table is initialized with zeroes via kvcalloc(), we can
	// skip the trap state (state == 0)
	for (state = 1; state < state_count; state++)
		perms_table[state] = dfa_user_allow(xmatch, state);

	return perms_table;
}

/**
 * unpack_profile - unpack a serialized profile
 * @e: serialized data extent information (NOT NULL)
@@ -727,13 +744,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
		info = "bad xmatch";
		goto fail;
	}
	/* xmatch_len is not optional if xmatch is set */
	/* neither xmatch_len not xmatch_perms are optional if xmatch is set */
	if (profile->xmatch) {
		if (!unpack_u32(e, &tmp, NULL)) {
			info = "missing xmatch len";
			goto fail;
		}
		profile->xmatch_len = tmp;

		profile->xmatch_perms = aa_compute_xmatch_perms(
			profile->xmatch);
	}

	/* disconnected attachment string is optional */