apparmor: compute xmatch permissions on profile load
authorMike Salvatore <mike.salvatore@canonical.com>
Sun, 31 May 2020 14:52:06 +0000 (10:52 -0400)
committerJohn Johansen <john.johansen@canonical.com>
Mon, 3 Oct 2022 21:49:02 +0000 (14:49 -0700)
Rather than computing xmatch permissions each time access is requested,
these permissions can be computed once on profile load and stored for
lookup.

Signed-off-by: Mike Salvatore <mike.salvatore@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/domain.c
security/apparmor/include/policy.h
security/apparmor/policy.c
security/apparmor/policy_unpack.c

index 2c99edd..22351b6 100644 (file)
@@ -339,7 +339,7 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
                        /* Check xattr value */
                        state = aa_dfa_match_len(profile->xmatch, state, value,
                                                 size);
-                       perm = dfa_user_allow(profile->xmatch, state);
+                       perm = profile->xmatch_perms[state];
                        if (!(perm & MAY_EXEC)) {
                                ret = -EINVAL;
                                goto out;
@@ -419,7 +419,7 @@ restart:
 
                        state = aa_dfa_leftmatch(profile->xmatch, DFA_START,
                                                 name, &count);
-                       perm = dfa_user_allow(profile->xmatch, state);
+                       perm = profile->xmatch_perms[state];
                        /* any accepting state means a valid match. */
                        if (perm & MAY_EXEC) {
                                int ret = 0;
index 639b5b2..128c6a9 100644 (file)
@@ -104,6 +104,7 @@ struct aa_data {
  * @attach: human readable attachment string
  * @xmatch: optional extended matching for unconfined executables names
  * @xmatch_len: xmatch prefix len, used to determine xmatch priority
+ * @xmatch_perms: precomputed permissions for the xmatch DFA indexed by state
  * @audit: the auditing mode of the profile
  * @mode: the enforcement mode of the profile
  * @path_flags: flags controlling path generation behavior
@@ -140,6 +141,7 @@ struct aa_profile {
        const char *attach;
        struct aa_dfa *xmatch;
        unsigned int xmatch_len;
+       u32 *xmatch_perms;
        enum audit_mode audit;
        long mode;
        u32 path_flags;
index fbdfcef..e2d23cd 100644 (file)
@@ -231,6 +231,7 @@ void aa_free_profile(struct aa_profile *profile)
        kfree_sensitive(profile->secmark);
        kfree_sensitive(profile->dirname);
        aa_put_dfa(profile->xmatch);
+       kvfree(profile->xmatch_perms);
        aa_put_dfa(profile->policy.dfa);
 
        if (profile->data) {
index 54175bc..70b7a35 100644 (file)
@@ -669,6 +669,23 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj)
        return strcmp(data->key, *key);
 }
 
+static u32 *aa_compute_xmatch_perms(struct aa_dfa *xmatch)
+{
+       u32 *perms_table;
+       int state;
+       int state_count = xmatch->tables[YYTD_ID_BASE]->td_lolen;
+
+       // DFAs are restricted from having a state_count of less than 2
+       perms_table = kvcalloc(state_count, sizeof(u32), GFP_KERNEL);
+
+       // Since perms_table is initialized with zeroes via kvcalloc(), we can
+       // skip the trap state (state == 0)
+       for (state = 1; state < state_count; state++)
+               perms_table[state] = dfa_user_allow(xmatch, state);
+
+       return perms_table;
+}
+
 /**
  * unpack_profile - unpack a serialized profile
  * @e: serialized data extent information (NOT NULL)
@@ -727,13 +744,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                info = "bad xmatch";
                goto fail;
        }
-       /* xmatch_len is not optional if xmatch is set */
+       /* neither xmatch_len not xmatch_perms are optional if xmatch is set */
        if (profile->xmatch) {
                if (!unpack_u32(e, &tmp, NULL)) {
                        info = "missing xmatch len";
                        goto fail;
                }
                profile->xmatch_len = tmp;
+
+               profile->xmatch_perms = aa_compute_xmatch_perms(
+                       profile->xmatch);
        }
 
        /* disconnected attachment string is optional */