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

apparmor: group dfa policydb unpacking



There are currently three policydb rule groupings (xmatch, file,
policydb) that each do their own slightly different thing. Group them
into a single routine and unify.

This extends/unifies dfa features by
- all dfas are allowed having an optional start field
- all dfas are allowed having a string/transition table

Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent a0792e2c
Loading
Loading
Loading
Loading
+63 −38
Original line number Diff line number Diff line
@@ -648,6 +648,54 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
	return false;
}

static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
		      bool required_dfa, bool required_trans,
		      const char **info)
{
	int i;

	policy->dfa = unpack_dfa(e);
	if (IS_ERR(policy->dfa)) {
		int error = PTR_ERR(policy->dfa);

		policy->dfa = NULL;
		*info = "failed to unpack - dfa";
		return error;
	} else if (!policy->dfa) {
		if (required_dfa) {
			*info = "missing required dfa";
			return -EPROTO;
		}
		goto out;
	}

	/*
	 * only unpack the following if a dfa is present
	 *
	 * sadly start was given different names for file and policydb
	 * but since it is optional we can try both
	 */
	if (!unpack_u32(e, &policy->start[0], "start"))
		/* default start state */
		policy->start[0] = DFA_START;
	if (!unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) {
		/* default start state for xmatch and file dfa */
		policy->start[AA_CLASS_FILE] = DFA_START;
	}	/* setup class index */
	for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) {
		policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0],
					       i);
	}
	if (!unpack_trans_table(e, &policy->trans) && required_trans) {
		*info = "failed to unpack profile transition table";
		return -EPROTO;
	}
	/* TODO: move compat mapping here, requires dfa merging first */

out:
	return 0;
}

static u32 strhash(const void *data, u32 len, u32 seed)
{
	const char * const *key = data;
@@ -679,7 +727,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
	struct rhashtable_params params = { 0 };
	char *key = NULL;
	struct aa_data *data;
	int i, error = -EPROTO;
	int error = -EPROTO;
	kernel_cap_t tmpcap;
	u32 tmp;

@@ -714,13 +762,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
	(void) unpack_str(e, &profile->attach, "attach");

	/* xmatch is optional and may be NULL */
	profile->xmatch.dfa = unpack_dfa(e);
	if (IS_ERR(profile->xmatch.dfa)) {
		error = PTR_ERR(profile->xmatch.dfa);
		profile->xmatch.dfa = NULL;
		info = "bad xmatch";
	error = unpack_pdb(e, &profile->xmatch, false, false, &info);
	if (error)
		goto fail;
	}

	/* neither xmatch_len not xmatch_perms are optional if xmatch is set */
	if (profile->xmatch.dfa) {
		if (!unpack_u32(e, &tmp, NULL)) {
@@ -838,25 +883,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
	if (unpack_nameX(e, AA_STRUCT, "policydb")) {
		/* generic policy dfa - optional and may be NULL */
		info = "failed to unpack policydb";
		profile->policy.dfa = unpack_dfa(e);
		if (IS_ERR(profile->policy.dfa)) {
			error = PTR_ERR(profile->policy.dfa);
			profile->policy.dfa = NULL;
			goto fail;
		} else if (!profile->policy.dfa) {
			error = -EPROTO;
		error = unpack_pdb(e, &profile->policy, true, false, &info);
		if (error)
			goto fail;
		}
		if (!unpack_u32(e, &profile->policy.start[0], "start"))
			/* default start state */
			profile->policy.start[0] = DFA_START;
		/* setup class index */
		for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) {
			profile->policy.start[i] =
		/* Fixup: drop when we get rid of start array */
		if (aa_dfa_next(profile->policy.dfa, profile->policy.start[0],
				AA_CLASS_FILE))
			profile->policy.start[AA_CLASS_FILE] =
			  aa_dfa_next(profile->policy.dfa,
				      profile->policy.start[0],
					    i);
		}
				      AA_CLASS_FILE);
		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
			goto fail;
		if (aa_compat_map_policy(&profile->policy, e->version)) {
@@ -867,25 +903,14 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
		profile->policy.dfa = aa_get_dfa(nulldfa);

	/* get file rules */
	profile->file.dfa = unpack_dfa(e);
	if (IS_ERR(profile->file.dfa)) {
		error = PTR_ERR(profile->file.dfa);
		profile->file.dfa = NULL;
		info = "failed to unpack profile file rules";
	error = unpack_pdb(e, &profile->file, false, true, &info);
	if (error) {
		goto fail;
	} else if (profile->file.dfa) {
		if (!unpack_u32(e, &profile->file.start[AA_CLASS_FILE],
				"dfa_start"))
			/* default start state */
			profile->file.start[AA_CLASS_FILE] = DFA_START;
		if (aa_compat_map_file(&profile->file)) {
			info = "failed to remap file permission table";
			goto fail;
		}
		if (!unpack_trans_table(e, &profile->file.trans)) {
			info = "failed to unpack profile transition table";
			goto fail;
		}
	} else if (profile->policy.dfa &&
		   profile->policy.start[AA_CLASS_FILE]) {
		profile->file.dfa = aa_get_dfa(profile->policy.dfa);