summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-08-08 22:01:01 +0200
committerJohn Johansen <john.johansen@canonical.com>2018-02-09 20:30:02 +0100
commitd901d6a298dc6e9105b9dc091d65b043e9f8c9a6 (patch)
treea57465d5598a1dbdba3f165e85f74b0a4d407326
parentapparmor: dfa add support for state differential encoding (diff)
downloadlinux-d901d6a298dc6e9105b9dc091d65b043e9f8c9a6.tar.xz
linux-d901d6a298dc6e9105b9dc091d65b043e9f8c9a6.zip
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>
-rw-r--r--security/apparmor/match.c116
1 files changed, 68 insertions, 48 deletions
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index 70cdcb3c3b25..7ae6ed9d69dd 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -136,8 +136,8 @@ fail:
}
/**
- * verify_dfa - verify that transitions and states in the tables are in bounds.
- * @dfa: dfa to test (NOT NULL)
+ * verify_table_headers - verify that the tables headers are as expected
+ * @tables - array of dfa tables to check (NOT NULL)
* @flags: flags controlling what type of accept table are acceptable
*
* 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
*/
-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;
/* check that required tables exist */
- if (!(dfa->tables[YYTD_ID_DEF] &&
- dfa->tables[YYTD_ID_BASE] &&
- dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
+ if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] &&
+ tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK]))
goto out;
/* 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 (!dfa->tables[YYTD_ID_ACCEPT])
+ if (!tables[YYTD_ID_ACCEPT])
goto out;
- if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
+ if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen)
goto out;
}
if (ACCEPT2_FLAGS(flags)) {
- if (!dfa->tables[YYTD_ID_ACCEPT2])
+ if (!tables[YYTD_ID_ACCEPT2])
goto out;
- if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
+ if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen)
goto out;
}
- if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
+ if (state_count != tables[YYTD_ID_DEF]->td_lolen)
goto out;
/* next.size == chk.size */
- trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
- if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
+ trans_count = tables[YYTD_ID_NXT]->td_lolen;
+ if (trans_count != tables[YYTD_ID_CHK]->td_lolen)
goto out;
/* if equivalence classes then its table size must be 256 */
- if (dfa->tables[YYTD_ID_EC] &&
- dfa->tables[YYTD_ID_EC]->td_lolen != 256)
+ if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256)
goto out;
- if (flags & DFA_FLAG_VERIFY_STATES) {
- 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) {
- printk(KERN_ERR "AppArmor DFA next/check upper "
- "bounds error\n");
- goto out;
- }
- }
+ error = 0;
+out:
+ return error;
+}
- 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;
+/**
+ * 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++) {
+ 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 */
- if (flags & DFA_FLAG_VERIFY_STATES) {
+ for (i = 0; i < state_count; i++) {
size_t j, k;
- for (i = 0; i < state_count; i++) {
- for (j = i;
- (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
- !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
- j = k) {
- k = DEFAULT_TABLE(dfa)[j];
- if (j == k)
- goto out;
- if (k < j)
- break; /* already verified */
- BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
- }
+ for (j = i;
+ (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
+ !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
+ j = k) {
+ k = DEFAULT_TABLE(dfa)[j];
+ if (j == k)
+ goto out;
+ if (k < j)
+ break; /* already verified */
+ BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
}
}
error = 0;
+
out:
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);
table = NULL;
}
-
- error = verify_dfa(dfa, flags);
+ error = verify_table_headers(dfa->tables, flags);
if (error)
goto fail;
+ if (flags & DFA_FLAG_VERIFY_STATES) {
+ error = verify_dfa(dfa);
+ if (error)
+ goto fail;
+ }
+
return dfa;
fail: