Commit 98b824ff authored by John Johansen's avatar John Johansen
Browse files

apparmor: refcount the pdb



With the move to permission tables the dfa is no longer a stand
alone entity when used, needing a minimum of a permission table.
However it still could be shared among different pdbs each using
a different permission table.

Instead of duping the permission table when sharing a pdb, add a
refcount to the pdb so it can be easily shared.

Reviewed-by: default avatarGeorgia Garcia <georgia.garcia@canonical.com>
Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 75c77e9e
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -619,23 +619,23 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,

	if (profile_unconfined(profile))
		return;
	if (rules->file.dfa && *match_str == AA_CLASS_FILE) {
		state = aa_dfa_match_len(rules->file.dfa,
					 rules->file.start[AA_CLASS_FILE],
	if (rules->file->dfa && *match_str == AA_CLASS_FILE) {
		state = aa_dfa_match_len(rules->file->dfa,
					 rules->file->start[AA_CLASS_FILE],
					 match_str + 1, match_len - 1);
		if (state) {
			struct path_cond cond = { };

			tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
			tmp = *(aa_lookup_fperms(rules->file, state, &cond));
		}
	} else if (rules->policy.dfa) {
	} else if (rules->policy->dfa) {
		if (!RULE_MEDIATES(rules, *match_str))
			return;	/* no change to current perms */
		state = aa_dfa_match_len(rules->policy.dfa,
					 rules->policy.start[0],
		state = aa_dfa_match_len(rules->policy->dfa,
					 rules->policy->start[0],
					 match_str, match_len);
		if (state)
			tmp = *aa_lookup_perms(&rules->policy, state);
			tmp = *aa_lookup_perms(rules->policy, state);
	}
	aa_apply_modes_to_perms(profile, &tmp);
	aa_perms_accum_raw(perms, &tmp);
@@ -1096,7 +1096,7 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v)
	struct aa_profile *profile = labels_profile(label);
	if (profile->attach.xmatch_str)
		seq_printf(seq, "%s\n", profile->attach.xmatch_str);
	else if (profile->attach.xmatch.dfa)
	else if (profile->attach.xmatch->dfa)
		seq_puts(seq, "<unknown>\n");
	else
		seq_printf(seq, "%s\n", profile->base.name);
+30 −30
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ static int may_change_ptraced_domain(const struct cred *to_cred,
/**** TODO: dedup to aa_label_match - needs perm and dfa, merging
 * specifically this is an exact copy of aa_label_match except
 * aa_compute_perms is replaced with aa_compute_fperms
 * and policy.dfa with file.dfa
 * and policy->dfa with file->dfa
 ****/
/* match a profile and its associated ns component if needed
 * Assumes visibility test has already been done.
@@ -93,16 +93,16 @@ static inline aa_state_t match_component(struct aa_profile *profile,
	const char *ns_name;

	if (stack)
		state = aa_dfa_match(rules->file.dfa, state, "&");
		state = aa_dfa_match(rules->file->dfa, state, "&");
	if (profile->ns == tp->ns)
		return aa_dfa_match(rules->file.dfa, state, tp->base.hname);
		return aa_dfa_match(rules->file->dfa, state, tp->base.hname);

	/* try matching with namespace name and then profile */
	ns_name = aa_ns_name(profile->ns, tp->ns, true);
	state = aa_dfa_match_len(rules->file.dfa, state, ":", 1);
	state = aa_dfa_match(rules->file.dfa, state, ns_name);
	state = aa_dfa_match_len(rules->file.dfa, state, ":", 1);
	return aa_dfa_match(rules->file.dfa, state, tp->base.hname);
	state = aa_dfa_match_len(rules->file->dfa, state, ":", 1);
	state = aa_dfa_match(rules->file->dfa, state, ns_name);
	state = aa_dfa_match_len(rules->file->dfa, state, ":", 1);
	return aa_dfa_match(rules->file->dfa, state, tp->base.hname);
}

/**
@@ -150,12 +150,12 @@ static int label_compound_match(struct aa_profile *profile,
	label_for_each_cont(i, label, tp) {
		if (!aa_ns_visible(profile->ns, tp->ns, subns))
			continue;
		state = aa_dfa_match(rules->file.dfa, state, "//&");
		state = aa_dfa_match(rules->file->dfa, state, "//&");
		state = match_component(profile, tp, false, state);
		if (!state)
			goto fail;
	}
	*perms = *(aa_lookup_fperms(&(rules->file), state, &cond));
	*perms = *(aa_lookup_fperms(rules->file, state, &cond));
	aa_apply_modes_to_perms(profile, perms);
	if ((perms->allow & request) != request)
		return -EACCES;
@@ -210,7 +210,7 @@ static int label_components_match(struct aa_profile *profile,
	return 0;

next:
	tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
	tmp = *(aa_lookup_fperms(rules->file, state, &cond));
	aa_apply_modes_to_perms(profile, &tmp);
	aa_perms_accum(perms, &tmp);
	label_for_each_cont(i, label, tp) {
@@ -219,7 +219,7 @@ static int label_components_match(struct aa_profile *profile,
		state = match_component(profile, tp, stack, start);
		if (!state)
			goto fail;
		tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
		tmp = *(aa_lookup_fperms(rules->file, state, &cond));
		aa_apply_modes_to_perms(profile, &tmp);
		aa_perms_accum(perms, &tmp);
	}
@@ -317,7 +317,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
	might_sleep();

	/* transition from exec match to xattr set */
	state = aa_dfa_outofband_transition(attach->xmatch.dfa, state);
	state = aa_dfa_outofband_transition(attach->xmatch->dfa, state);
	d = bprm->file->f_path.dentry;

	for (i = 0; i < attach->xattr_count; i++) {
@@ -331,20 +331,20 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
			 * that not present xattr can be distinguished from a 0
			 * length value or rule that matches any value
			 */
			state = aa_dfa_null_transition(attach->xmatch.dfa,
			state = aa_dfa_null_transition(attach->xmatch->dfa,
						       state);
			/* Check xattr value */
			state = aa_dfa_match_len(attach->xmatch.dfa, state,
			state = aa_dfa_match_len(attach->xmatch->dfa, state,
						 value, size);
			index = ACCEPT_TABLE(attach->xmatch.dfa)[state];
			perm = attach->xmatch.perms[index].allow;
			index = ACCEPT_TABLE(attach->xmatch->dfa)[state];
			perm = attach->xmatch->perms[index].allow;
			if (!(perm & MAY_EXEC)) {
				ret = -EINVAL;
				goto out;
			}
		}
		/* transition to next element */
		state = aa_dfa_outofband_transition(attach->xmatch.dfa, state);
		state = aa_dfa_outofband_transition(attach->xmatch->dfa, state);
		if (size < 0) {
			/*
			 * No xattr match, so verify if transition to
@@ -413,16 +413,16 @@ static struct aa_label *find_attach(const struct linux_binprm *bprm,
		 * as another profile, signal a conflict and refuse to
		 * match.
		 */
		if (attach->xmatch.dfa) {
		if (attach->xmatch->dfa) {
			unsigned int count;
			aa_state_t state;
			u32 index, perm;

			state = aa_dfa_leftmatch(attach->xmatch.dfa,
					attach->xmatch.start[AA_CLASS_XMATCH],
			state = aa_dfa_leftmatch(attach->xmatch->dfa,
					attach->xmatch->start[AA_CLASS_XMATCH],
					name, &count);
			index = ACCEPT_TABLE(attach->xmatch.dfa)[state];
			perm = attach->xmatch.perms[index].allow;
			index = ACCEPT_TABLE(attach->xmatch->dfa)[state];
			perm = attach->xmatch->perms[index].allow;
			/* any accepting state means a valid match. */
			if (perm & MAY_EXEC) {
				int ret = 0;
@@ -525,7 +525,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
	/* TODO: move lookup parsing to unpack time so this is a straight
	 *       index into the resultant label
	 */
	for (*name = rules->file.trans.table[index]; !label && *name;
	for (*name = rules->file->trans.table[index]; !label && *name;
	     *name = next_name(xtype, *name)) {
		if (xindex & AA_X_CHILD) {
			struct aa_profile *new_profile;
@@ -579,7 +579,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
		break;
	case AA_X_TABLE:
		/* TODO: fix when perm mapping done at unload */
		stack = rules->file.trans.table[xindex & AA_X_INDEX_MASK];
		stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK];
		if (*stack != '&') {
			/* released by caller */
			new = x_table_lookup(profile, xindex, lookupname);
@@ -638,7 +638,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
						    typeof(*rules), list);
	struct aa_label *new = NULL;
	const char *info = NULL, *name = NULL, *target = NULL;
	aa_state_t state = rules->file.start[AA_CLASS_FILE];
	aa_state_t state = rules->file->start[AA_CLASS_FILE];
	struct aa_perms perms = {};
	bool nonewprivs = false;
	int error = 0;
@@ -672,7 +672,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
	}

	/* find exec permissions for name */
	state = aa_str_perms(&(rules->file), state, name, cond, &perms);
	state = aa_str_perms(rules->file, state, name, cond, &perms);
	if (perms.allow & MAY_EXEC) {
		/* exec permission determine how to transition */
		new = x_to_label(profile, bprm, name, perms.xindex, &target,
@@ -738,7 +738,7 @@ static int profile_onexec(const struct cred *subj_cred,
{
	struct aa_ruleset *rules = list_first_entry(&profile->rules,
						    typeof(*rules), list);
	aa_state_t state = rules->file.start[AA_CLASS_FILE];
	aa_state_t state = rules->file->start[AA_CLASS_FILE];
	struct aa_perms perms = {};
	const char *xname = NULL, *info = "change_profile onexec";
	int error = -EACCES;
@@ -771,7 +771,7 @@ static int profile_onexec(const struct cred *subj_cred,
	}

	/* find exec permissions for name */
	state = aa_str_perms(&(rules->file), state, xname, cond, &perms);
	state = aa_str_perms(rules->file, state, xname, cond, &perms);
	if (!(perms.allow & AA_MAY_ONEXEC)) {
		info = "no change_onexec valid for executable";
		goto audit;
@@ -780,7 +780,7 @@ static int profile_onexec(const struct cred *subj_cred,
	 * onexec permission is linked to exec with a standard pairing
	 * exec\0change_profile
	 */
	state = aa_dfa_null_transition(rules->file.dfa, state);
	state = aa_dfa_null_transition(rules->file->dfa, state);
	error = change_profile_perms(profile, onexec, stack, AA_MAY_ONEXEC,
				     state, &perms);
	if (error) {
@@ -1300,7 +1300,7 @@ static int change_profile_perms_wrapper(const char *op, const char *name,

	if (!error)
		error = change_profile_perms(profile, target, stack, request,
					     rules->file.start[AA_CLASS_FILE],
					     rules->file->start[AA_CLASS_FILE],
					     perms);
	if (error)
		error = aa_audit_file(subj_cred, profile, perms, op, request,
+6 −6
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ static int __aa_path_perm(const char *op, const struct cred *subj_cred,

	if (profile_unconfined(profile))
		return 0;
	aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE],
	aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
		     name, cond, perms);
	if (request & ~perms->allow)
		e = -EACCES;
@@ -353,16 +353,16 @@ static int profile_path_link(const struct cred *subj_cred,

	error = -EACCES;
	/* aa_str_perms - handles the case of the dfa being NULL */
	state = aa_str_perms(&(rules->file),
			     rules->file.start[AA_CLASS_FILE], lname,
	state = aa_str_perms(rules->file,
			     rules->file->start[AA_CLASS_FILE], lname,
			     cond, &lperms);

	if (!(lperms.allow & AA_MAY_LINK))
		goto audit;

	/* test to see if target can be paired with link */
	state = aa_dfa_null_transition(rules->file.dfa, state);
	aa_str_perms(&(rules->file), state, tname, cond, &perms);
	state = aa_dfa_null_transition(rules->file->dfa, state);
	aa_str_perms(rules->file, state, tname, cond, &perms);

	/* force audit/quiet masks for link are stored in the second entry
	 * in the link pair.
@@ -384,7 +384,7 @@ static int profile_path_link(const struct cred *subj_cred,
	/* Do link perm subset test requiring allowed permission on link are
	 * a subset of the allowed permissions on target.
	 */
	aa_str_perms(&(rules->file), rules->file.start[AA_CLASS_FILE],
	aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE],
		     tname, cond, &perms);

	/* AA_MAY_LINK is not considered in the subset test */
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#include "match.h"

extern struct aa_dfa *stacksplitdfa;

/*
 * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
 * which is not related to profile accesses.
+0 −6
Original line number Diff line number Diff line
@@ -102,9 +102,6 @@ struct aa_dfa {
	struct table_header *tables[YYTD_ID_TSIZE];
};

extern struct aa_dfa *nulldfa;
extern struct aa_dfa *stacksplitdfa;

#define byte_to_byte(X) (X)

#define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX)	\
@@ -122,9 +119,6 @@ static inline size_t table_size(size_t len, size_t el_size)
	return ALIGN(sizeof(struct table_header) + len * el_size, 8);
}

int aa_setup_dfa_engine(void);
void aa_teardown_dfa_engine(void);

#define aa_state_t unsigned int

struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
Loading