summaryrefslogtreecommitdiff
path: root/security/apparmor/policy_unpack.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2020-11-17 12:38:16 +0300
committerJohn Johansen <john.johansen@canonical.com>2022-10-04 00:49:03 +0300
commite2967ede22978f132cd52929edff96c701bde0eb (patch)
treebe2a22d52d6bd15e44ee25a507fb589d464951ff /security/apparmor/policy_unpack.c
parente48ffd24c1d87dba227225615790cd059a707adb (diff)
downloadlinux-e2967ede22978f132cd52929edff96c701bde0eb.tar.xz
apparmor: compute policydb permission on profile load
Rather than computing policydb permissions for each access permissions can be computed once on profile load and stored for lookup. Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/policy_unpack.c')
-rw-r--r--security/apparmor/policy_unpack.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 44910c201c49..ed063385a83b 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -756,7 +756,7 @@ static struct aa_perms *compute_fperms(struct aa_dfa *dfa)
state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
/* DFAs are restricted from having a state_count of less than 2 */
- table = kvzalloc(state_count * 2 * sizeof(struct aa_perms), GFP_KERNEL);
+ table = kvcalloc(state_count * 2, sizeof(struct aa_perms), GFP_KERNEL);
if (!table)
return NULL;
@@ -789,6 +789,54 @@ static struct aa_perms *compute_xmatch_perms(struct aa_dfa *xmatch)
return perms_table;
}
+static u32 map_other(u32 x)
+{
+ return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
+ ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
+ ((x & 0x60) << 19); /* SETOPT/GETOPT */
+}
+
+static struct aa_perms compute_perms_entry(struct aa_dfa *dfa,
+ unsigned int state)
+{
+ struct aa_perms perms = { };
+
+ perms.allow = dfa_user_allow(dfa, state);
+ perms.audit = dfa_user_audit(dfa, state);
+ perms.quiet = dfa_user_quiet(dfa, state);
+
+ /* for v5 perm mapping in the policydb, the other set is used
+ * to extend the general perm set
+ */
+
+ perms.allow |= map_other(dfa_other_allow(dfa, state));
+ perms.audit |= map_other(dfa_other_audit(dfa, state));
+ perms.quiet |= map_other(dfa_other_quiet(dfa, state));
+
+ return perms;
+}
+
+static struct aa_perms *compute_perms(struct aa_dfa *dfa)
+{
+ int state;
+ int state_count;
+ struct aa_perms *table;
+
+ AA_BUG(!dfa);
+
+ state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+ /* DFAs are restricted from having a state_count of less than 2 */
+ table = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL);
+ if (!table)
+ return NULL;
+
+ /* zero init so skip the trap state (state == 0) */
+ for (state = 1; state < state_count; state++)
+ table[state] = compute_perms_entry(dfa, state);
+
+ return table;
+}
+
/**
* unpack_profile - unpack a serialized profile
* @e: serialized data extent information (NOT NULL)
@@ -986,6 +1034,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
} else
profile->policy.dfa = aa_get_dfa(nulldfa);
+ profile->policy.perms = compute_perms(profile->policy.dfa);
+ if (!profile->policy.perms) {
+ info = "failed to remap policydb permission table";
+ goto fail;
+ }
/* get file rules */
profile->file.dfa = unpack_dfa(e);