apparmor: dfa add support for state differential encoding
authorJohn Johansen <john.johansen@canonical.com>
Tue, 8 Aug 2017 19:10:50 +0000 (12:10 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Fri, 9 Feb 2018 19:30:01 +0000 (11:30 -0800)
State differential encoding can provide better compression for
apparmor policy, without having significant impact on match time.

Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/include/match.h
security/apparmor/match.c

index cd8aeab6ac570dbc094667d6e58a998700e2b337..e0de00bd16a867fcb08a5dfb05db44ecc1ca6991 100644 (file)
@@ -40,6 +40,7 @@
  */
 
 #define YYTH_MAGIC     0x1B5E783D
+#define YYTH_FLAG_DIFF_ENCODE  1
 
 struct table_set_header {
        u32 th_magic;           /* YYTH_MAGIC */
@@ -164,4 +165,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa)
                kref_put(&dfa->count, aa_dfa_free_kref);
 }
 
+#define MATCH_FLAG_DIFF_ENCODE 0x80000000
+#define MARK_DIFF_ENCODE 0x40000000
+
 #endif /* __AA_MATCH_H */
index aeac68c58689ef45b40d27165e405b884ee2217f..70cdcb3c3b25177b1f8e04f7d5d37d21068160e0 100644 (file)
@@ -185,7 +185,8 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
 
        if (flags & DFA_FLAG_VERIFY_STATES) {
                for (i = 0; i < state_count; i++) {
-                       if (DEFAULT_TABLE(dfa)[i] >= state_count)
+                       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 "
@@ -202,6 +203,24 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
                }
        }
 
+       /* Now that all the other tables are verified, verify diffencoding */
+       if (flags & DFA_FLAG_VERIFY_STATES) {
+               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;
+                       }
+               }
+       }
        error = 0;
 out:
        return error;
@@ -274,6 +293,9 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
                goto fail;
 
        dfa->flags = ntohs(*(__be16 *) (data + 12));
+       if (dfa->flags != 0 && dfa->flags != YYTH_FLAG_DIFF_ENCODE)
+               goto fail;
+
        data += hsize;
        size -= hsize;
 
@@ -335,6 +357,8 @@ do {                                                        \
        unsigned int pos = base_idx(b) + (C);           \
        if ((check)[pos] != (state)) {                  \
                (state) = (def)[(state)];               \
+               if (b & MATCH_FLAG_DIFF_ENCODE)         \
+                       continue;                       \
                break;                                  \
        }                                               \
        (state) = (next)[pos];                          \