forked from Minki/linux
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: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
031dcc8f4e
commit
d901d6a298
@ -136,8 +136,8 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,83 +145,98 @@ fail:
|
|||||||
*
|
*
|
||||||
* 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;
|
||||||
for (i = 0; i < state_count; i++) {
|
out:
|
||||||
if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
|
return error;
|
||||||
(DEFAULT_TABLE(dfa)[i] >= state_count))
|
}
|
||||||
goto out;
|
|
||||||
if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
|
|
||||||
printk(KERN_ERR "AppArmor DFA next/check upper "
|
|
||||||
"bounds error\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < trans_count; i++) {
|
/**
|
||||||
if (NEXT_TABLE(dfa)[i] >= state_count)
|
* verify_dfa - verify that transitions and states in the tables are in bounds.
|
||||||
goto out;
|
* @dfa: dfa to test (NOT NULL)
|
||||||
if (CHECK_TABLE(dfa)[i] >= state_count)
|
*
|
||||||
goto out;
|
* 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++) {
|
||||||
|
if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
|
||||||
|
(DEFAULT_TABLE(dfa)[i] >= state_count))
|
||||||
|
goto out;
|
||||||
|
if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
|
||||||
|
pr_err("AppArmor DFA next/check upper bounds error\n");
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < trans_count; i++) {
|
||||||
|
if (NEXT_TABLE(dfa)[i] >= state_count)
|
||||||
|
goto out;
|
||||||
|
if (CHECK_TABLE(dfa)[i] >= state_count)
|
||||||
|
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);
|
j = k) {
|
||||||
j = k) {
|
k = DEFAULT_TABLE(dfa)[j];
|
||||||
k = DEFAULT_TABLE(dfa)[j];
|
if (j == k)
|
||||||
if (j == k)
|
goto out;
|
||||||
goto out;
|
if (k < j)
|
||||||
if (k < j)
|
break; /* already verified */
|
||||||
break; /* already verified */
|
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,11 +353,16 @@ 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);
|
||||||
error = verify_dfa(dfa, flags);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (flags & DFA_FLAG_VERIFY_STATES) {
|
||||||
|
error = verify_dfa(dfa);
|
||||||
|
if (error)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
return dfa;
|
return dfa;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
Loading…
Reference in New Issue
Block a user