apparmor: dfa split verification of table headers
authorJohn Johansen <john.johansen@canonical.com>
Tue, 8 Aug 2017 20:01:01 +0000 (13:01 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Fri, 9 Feb 2018 19:30:02 +0000 (11:30 -0800)
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>
security/apparmor/match.c

index 70cdcb3c3b25177b1f8e04f7d5d37d21068160e0..7ae6ed9d69dd801d784ea54485c37e91211bb9cf 100644 (file)
@@ -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: