summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Salvatore <mike.salvatore@canonical.com>2020-05-31 17:52:06 +0300
committerJohn Johansen <john.johansen@canonical.com>2022-10-04 00:49:02 +0300
commitb5b57993504f91785fa70e002e5e494fb549726e (patch)
tree3d3a6cc40d0949486554351e6889ed5fc594fb98
parent408d53e923bd852d5d80243a642004163db53a87 (diff)
downloadlinux-b5b57993504f91785fa70e002e5e494fb549726e.tar.xz
apparmor: compute xmatch permissions on profile load
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>
-rw-r--r--security/apparmor/domain.c4
-rw-r--r--security/apparmor/include/policy.h2
-rw-r--r--security/apparmor/policy.c1
-rw-r--r--security/apparmor/policy_unpack.c22
4 files changed, 26 insertions, 3 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 2c99edd8953a..22351b6d71e6 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -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;
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 639b5b248e63..128c6a9430d4 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -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;
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index fbdfcef91c61..e2d23cd85cd2 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -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) {
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 54175bca4256..70b7a35b5b96 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -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 */