]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
apparmor: add outofband transition and use it in xattr match
authorJohn Johansen <john.johansen@canonical.com>
Tue, 30 Jul 2019 09:42:13 +0000 (02:42 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Tue, 21 Jan 2020 14:00:20 +0000 (06:00 -0800)
There are cases where the a special out of band transition that can
not be triggered by input is useful in separating match conditions
in the dfa encoding.

The null_transition is currently used as an out of band transition
for match conditions that can not contain a \0 in their input
but apparmor needs an out of band transition for cases where
the match condition is allowed to contain any input character.

Achieve this by allowing for an explicit transition out of input
range that can only be triggered by code.

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

index be6dc548d3076f1ba07e9d9e8fa2d6daf4dad468..d7a179cdaa1e6e2a93f6668233e628c03e9d8a79 100644 (file)
@@ -591,7 +591,7 @@ static __poll_t ns_revision_poll(struct file *file, poll_table *pt)
 
 void __aa_bump_ns_revision(struct aa_ns *ns)
 {
-       WRITE_ONCE(ns->revision, ns->revision + 1);
+       WRITE_ONCE(ns->revision, READ_ONCE(ns->revision) + 1);
        wake_up_interruptible(&ns->wait);
 }
 
@@ -2331,6 +2331,8 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
 static struct aa_sfs_entry aa_sfs_entry_policy[] = {
        AA_SFS_DIR("versions",                  aa_sfs_entry_versions),
        AA_SFS_FILE_BOOLEAN("set_load",         1),
+       /* number of out of band transitions supported */
+       AA_SFS_FILE_U64("outofband",            MAX_OOB_SUPPORTED),
        { }
 };
 
index f73ba303ba246442bd4febfbbb2ae79cc3ca736c..0a91d5f7d0e9966e19c72ec931aeef928d14f2e9 100644 (file)
@@ -320,8 +320,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
        might_sleep();
 
        /* transition from exec match to xattr set */
-       state = aa_dfa_null_transition(profile->xmatch, state);
-
+       state = aa_dfa_outofband_transition(profile->xmatch, state);
        d = bprm->file->f_path.dentry;
 
        for (i = 0; i < profile->xattr_count; i++) {
@@ -330,7 +329,13 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
                if (size >= 0) {
                        u32 perm;
 
-                       /* Check the xattr value, not just presence */
+                       /*
+                        * Check the xattr presence before value. This ensure
+                        * that not present xattr can be distinguished from a 0
+                        * length value or rule that matches any value
+                        */
+                       state = aa_dfa_null_transition(profile->xmatch, state);
+                       /* Check xattr value */
                        state = aa_dfa_match_len(profile->xmatch, state, value,
                                                 size);
                        perm = dfa_user_allow(profile->xmatch, state);
@@ -340,7 +345,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
                        }
                }
                /* transition to next element */
-               state = aa_dfa_null_transition(profile->xmatch, state);
+               state = aa_dfa_outofband_transition(profile->xmatch, state);
                if (size < 0) {
                        /*
                         * No xattr match, so verify if transition to
index f280b046361e69f4c4b1575d748f852b3ce91e2b..8844895905881bad81dbce5e8336df6a3cf05d38 100644 (file)
 
 #define YYTH_MAGIC     0x1B5E783D
 #define YYTH_FLAG_DIFF_ENCODE  1
+#define YYTH_FLAG_OOB_TRANS    2
+#define YYTH_FLAGS (YYTH_FLAG_DIFF_ENCODE | YYTH_FLAG_OOB_TRANS)
+
+#define MAX_OOB_SUPPORTED      1
 
 struct table_set_header {
        u32 th_magic;           /* YYTH_MAGIC */
@@ -94,6 +98,7 @@ struct table_header {
 struct aa_dfa {
        struct kref count;
        u16 flags;
+       u32 max_oob;
        struct table_header *tables[YYTD_ID_TSIZE];
 };
 
@@ -127,6 +132,8 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
                          const char *str);
 unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
                         const char c);
+unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa,
+                                        unsigned int state);
 unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start,
                                const char *str, const char **retpos);
 unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
@@ -183,7 +190,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa)
 #define MARK_DIFF_ENCODE 0x40000000
 #define MATCH_FLAG_OOB_TRANSITION 0x20000000
 #define MATCH_FLAGS_MASK 0xff000000
-#define MATCH_FLAGS_VALID MATCH_FLAG_DIFF_ENCODE
+#define MATCH_FLAGS_VALID (MATCH_FLAG_DIFF_ENCODE | MATCH_FLAG_OOB_TRANSITION)
 #define MATCH_FLAGS_INVALID (MATCH_FLAGS_MASK & ~MATCH_FLAGS_VALID)
 
 #endif /* __AA_MATCH_H */
index 651dbb6e38b8142f9636fe0aab406f936bf101f0..e605b7d53fb4b632d15380881d3132d1a24836b4 100644 (file)
@@ -212,6 +212,16 @@ static int verify_dfa(struct aa_dfa *dfa)
                                goto out;
                        }
                }
+               if ((BASE_TABLE(dfa)[i] & MATCH_FLAG_OOB_TRANSITION)) {
+                       if (base_idx(BASE_TABLE(dfa)[i]) < dfa->max_oob) {
+                               pr_err("AppArmor DFA out of bad transition out of range");
+                               goto out;
+                       }
+                       if (!(dfa->flags & YYTH_FLAG_OOB_TRANS)) {
+                               pr_err("AppArmor DFA out of bad transition state without header flag");
+                               goto out;
+                       }
+               }
                if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
                        pr_err("AppArmor DFA next/check upper bounds error\n");
                        goto out;
@@ -314,9 +324,23 @@ 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)
+       if (dfa->flags & ~(YYTH_FLAGS))
                goto fail;
 
+       /*
+        * TODO: needed for dfa to support more than 1 oob
+        * if (dfa->flags & YYTH_FLAGS_OOB_TRANS) {
+        *      if (hsize < 16 + 4)
+        *              goto fail;
+        *      dfa->max_oob = ntol(*(__be32 *) (data + 16));
+        *      if (dfa->max <= MAX_OOB_SUPPORTED) {
+        *              pr_err("AppArmor DFA OOB greater than supported\n");
+        *              goto fail;
+        *      }
+        * }
+        */
+       dfa->max_oob = 1;
+
        data += hsize;
        size -= hsize;
 
@@ -505,6 +529,23 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
        return state;
 }
 
+unsigned int aa_dfa_outofband_transition(struct aa_dfa *dfa, unsigned int state)
+{
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+       u32 b = (base)[(state)];
+
+       if (!(b & MATCH_FLAG_OOB_TRANSITION))
+               return DFA_NOMATCH;
+
+       /* No Equivalence class remapping for outofband transitions */
+       match_char(state, def, base, next, check, -1);
+
+       return state;
+}
+
 /**
  * aa_dfa_match_until - traverse @dfa until accept state or end of input
  * @dfa: the dfa to match @str against  (NOT NULL)