summaryrefslogtreecommitdiffstats
path: root/security/apparmor/policy_unpack.c
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2018-02-08 12:37:19 -0800
committerJohn Johansen <john.johansen@canonical.com>2018-02-09 11:30:02 -0800
commit8e51f9087f4024d20f70f4d9831e1f45d8088331 (patch)
treea466a6dfa9ffd57b9919b89931bc18fbddb1517e /security/apparmor/policy_unpack.c
parenta0781209cb894e5115bb00c269b1d94c4b632d6a (diff)
downloadlinux-8e51f9087f4024d20f70f4d9831e1f45d8088331.tar.bz2
apparmor: Add support for attaching profiles via xattr, presence and value
Make it possible to tie Apparmor profiles to the presence of one or more extended attributes, and optionally their values. An example usecase for this is to automatically transition to a more privileged Apparmor profile if an executable has a valid IMA signature, which can then be appraised by the IMA subsystem. Signed-off-by: Matthew Garrett <mjg59@google.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/policy_unpack.c')
-rw-r--r--security/apparmor/policy_unpack.c85
1 files changed, 76 insertions, 9 deletions
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 40c8dc617b13..98d019185e57 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -203,6 +203,15 @@ static bool inbounds(struct aa_ext *e, size_t size)
return (size <= e->end - e->pos);
}
+static void *kvmemdup(const void *src, size_t len)
+{
+ void *p = kvmalloc(len, GFP_KERNEL);
+
+ if (p)
+ memcpy(p, src, len);
+ return p;
+}
+
/**
* aa_u16_chunck - test and do bounds checking for a u16 size based chunk
* @e: serialized data read head (NOT NULL)
@@ -522,6 +531,68 @@ fail:
return 0;
}
+static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
+{
+ void *pos = e->pos;
+
+ if (unpack_nameX(e, AA_STRUCT, "xattrs")) {
+ int i, size;
+
+ size = unpack_array(e, NULL);
+ profile->xattr_count = size;
+ profile->xattrs = kcalloc(size, sizeof(char *),
+ GFP_KERNEL);
+ if (!profile->xattrs)
+ goto fail;
+ for (i = 0; i < size; i++) {
+ if (!unpack_strdup(e, &profile->xattrs[i], NULL))
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+ }
+
+ if (unpack_nameX(e, AA_STRUCT, "xattr_values")) {
+ int i, size;
+
+ size = unpack_array(e, NULL);
+
+ /* Must be the same number of xattr values as xattrs */
+ if (size != profile->xattr_count)
+ goto fail;
+
+ profile->xattr_lens = kcalloc(size, sizeof(size_t),
+ GFP_KERNEL);
+ if (!profile->xattr_lens)
+ goto fail;
+
+ profile->xattr_values = kcalloc(size, sizeof(char *),
+ GFP_KERNEL);
+ if (!profile->xattr_values)
+ goto fail;
+
+ for (i = 0; i < size; i++) {
+ profile->xattr_lens[i] = unpack_blob(e,
+ &profile->xattr_values[i], NULL);
+ profile->xattr_values[i] =
+ kvmemdup(profile->xattr_values[i],
+ profile->xattr_lens[i]);
+ }
+
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+ }
+ return 1;
+
+fail:
+ e->pos = pos;
+ return 0;
+}
+
static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
{
void *pos = e->pos;
@@ -556,15 +627,6 @@ fail:
return 0;
}
-static void *kvmemdup(const void *src, size_t len)
-{
- void *p = kvmalloc(len, GFP_KERNEL);
-
- if (p)
- memcpy(p, src, len);
- return p;
-}
-
static u32 strhash(const void *data, u32 len, u32 seed)
{
const char * const *key = data;
@@ -719,6 +781,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
+ if (!unpack_xattrs(e, profile)) {
+ info = "failed to unpack profile xattrs";
+ goto fail;
+ }
+
if (!unpack_rlimits(e, profile)) {
info = "failed to unpack profile rlimits";
goto fail;