Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

apparmor: dfa split verification of table headers



separate the different types of verification so they are logically
separate and can be reused separate of each other.

Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 031dcc8f
Loading
Loading
Loading
Loading
+68 −48
Original line number Original line Diff line number Diff line
@@ -136,8 +136,8 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
}
}


/**
/**
 * verify_dfa - verify that transitions and states in the tables are in bounds.
 * verify_table_headers - verify that the tables headers are as expected
 * @dfa: dfa to test  (NOT NULL)
 * @tables - array of dfa tables to check (NOT NULL)
 * @flags: flags controlling what type of accept table are acceptable
 * @flags: flags controlling what type of accept table are acceptable
 *
 *
 * Assumes dfa has gone through the first pass verification done by unpacking
 * Assumes dfa has gone through the first pass verification done by unpacking
@@ -145,52 +145,69 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
 *
 *
 * Returns: %0 else error code on failure to verify
 * Returns: %0 else error code on failure to verify
 */
 */
static int verify_dfa(struct aa_dfa *dfa, int flags)
static int verify_table_headers(struct table_header **tables, int flags)
{
{
	size_t i, state_count, trans_count;
	size_t state_count, trans_count;
	int error = -EPROTO;
	int error = -EPROTO;


	/* check that required tables exist */
	/* check that required tables exist */
	if (!(dfa->tables[YYTD_ID_DEF] &&
	if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] &&
	      dfa->tables[YYTD_ID_BASE] &&
	      tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK]))
	      dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
		goto out;
		goto out;


	/* accept.size == default.size == base.size */
	/* accept.size == default.size == base.size */
	state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
	state_count = tables[YYTD_ID_BASE]->td_lolen;
	if (ACCEPT1_FLAGS(flags)) {
	if (ACCEPT1_FLAGS(flags)) {
		if (!dfa->tables[YYTD_ID_ACCEPT])
		if (!tables[YYTD_ID_ACCEPT])
			goto out;
			goto out;
		if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
		if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen)
			goto out;
			goto out;
	}
	}
	if (ACCEPT2_FLAGS(flags)) {
	if (ACCEPT2_FLAGS(flags)) {
		if (!dfa->tables[YYTD_ID_ACCEPT2])
		if (!tables[YYTD_ID_ACCEPT2])
			goto out;
			goto out;
		if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
		if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen)
			goto out;
			goto out;
	}
	}
	if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
	if (state_count != tables[YYTD_ID_DEF]->td_lolen)
		goto out;
		goto out;


	/* next.size == chk.size */
	/* next.size == chk.size */
	trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
	trans_count = tables[YYTD_ID_NXT]->td_lolen;
	if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
	if (trans_count != tables[YYTD_ID_CHK]->td_lolen)
		goto out;
		goto out;


	/* if equivalence classes then its table size must be 256 */
	/* if equivalence classes then its table size must be 256 */
	if (dfa->tables[YYTD_ID_EC] &&
	if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256)
	    dfa->tables[YYTD_ID_EC]->td_lolen != 256)
		goto out;
		goto out;


	if (flags & DFA_FLAG_VERIFY_STATES) {
	error = 0;
out:
	return error;
}

/**
 * verify_dfa - verify that transitions and states in the tables are in bounds.
 * @dfa: dfa to test  (NOT NULL)
 *
 * Assumes dfa has gone through the first pass verification done by unpacking
 * NOTE: this does not valid accept table values
 *
 * Returns: %0 else error code on failure to verify
 */
static int verify_dfa(struct aa_dfa *dfa)
{
	size_t i, state_count, trans_count;
	int error = EPROTO;

	state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
	trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
	for (i = 0; i < state_count; i++) {
	for (i = 0; i < state_count; i++) {
		if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
		if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
		    (DEFAULT_TABLE(dfa)[i] >= state_count))
		    (DEFAULT_TABLE(dfa)[i] >= state_count))
			goto out;
			goto out;
		if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
		if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
				printk(KERN_ERR "AppArmor DFA next/check upper "
			pr_err("AppArmor DFA next/check upper bounds error\n");
				       "bounds error\n");
			goto out;
			goto out;
		}
		}
	}
	}
@@ -201,13 +218,11 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
		if (CHECK_TABLE(dfa)[i] >= state_count)
		if (CHECK_TABLE(dfa)[i] >= state_count)
			goto out;
			goto out;
	}
	}
	}


	/* Now that all the other tables are verified, verify diffencoding */
	/* Now that all the other tables are verified, verify diffencoding */
	if (flags & DFA_FLAG_VERIFY_STATES) {
	for (i = 0; i < state_count; i++) {
		size_t j, k;
		size_t j, k;


		for (i = 0; i < state_count; i++) {
		for (j = i;
		for (j = i;
		     (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
		     (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
		     !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
		     !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
@@ -220,8 +235,8 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
			BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
			BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
		}
		}
	}
	}
	}
	error = 0;
	error = 0;

out:
out:
	return error;
	return error;
}
}
@@ -338,10 +353,15 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
		size -= table_size(table->td_lolen, table->td_flags);
		size -= table_size(table->td_lolen, table->td_flags);
		table = NULL;
		table = NULL;
	}
	}
	error = verify_table_headers(dfa->tables, flags);
	if (error)
		goto fail;


	error = verify_dfa(dfa, flags);
	if (flags & DFA_FLAG_VERIFY_STATES) {
		error = verify_dfa(dfa);
		if (error)
		if (error)
			goto fail;
			goto fail;
	}


	return dfa;
	return dfa;