]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - security/apparmor/policy_unpack.c
security: smack: Fix possible null-pointer dereferences in smack_socket_sock_rcv_skb()
[mirror_ubuntu-bionic-kernel.git] / security / apparmor / policy_unpack.c
index 59a1a25b7d43f209b594d61c7fd38fb4e0e50f37..59b2def1dc0ca69d54cc3578cb9f013a4068327e 100644 (file)
@@ -206,16 +206,21 @@ static bool inbounds(struct aa_ext *e, size_t size)
 static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
 {
        size_t size = 0;
+       void *pos = e->pos;
 
        if (!inbounds(e, sizeof(u16)))
-               return 0;
+               goto fail;
        size = le16_to_cpu(get_unaligned((__le16 *) e->pos));
        e->pos += sizeof(__le16);
        if (!inbounds(e, size))
-               return 0;
+               goto fail;
        *chunk = e->pos;
        e->pos += size;
        return size;
+
+fail:
+       e->pos = pos;
+       return 0;
 }
 
 /* unpack control byte */
@@ -259,7 +264,7 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
                char *tag = NULL;
                size_t size = unpack_u16_chunk(e, &tag);
                /* if a name is specified it must match. otherwise skip tag */
-               if (name && (!size || strcmp(name, tag)))
+               if (name && (!size || tag[size-1] != '\0' || strcmp(name, tag)))
                        goto fail;
        } else if (name) {
                /* if a name is specified and there is no name tag fail */
@@ -275,51 +280,81 @@ fail:
        return 0;
 }
 
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
+{
+       if (unpack_nameX(e, AA_U16, name)) {
+               if (!inbounds(e, sizeof(u16)))
+                       return 0;
+               if (data)
+                       *data = le16_to_cpu(get_unaligned((__le16 *) e->pos));
+               e->pos += sizeof(u16);
+               return 1;
+       }
+       return 0;
+}
+
 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
 {
+       void *pos = e->pos;
+
        if (unpack_nameX(e, AA_U32, name)) {
                if (!inbounds(e, sizeof(u32)))
-                       return 0;
+                       goto fail;
                if (data)
                        *data = le32_to_cpu(get_unaligned((__le32 *) e->pos));
                e->pos += sizeof(u32);
                return 1;
        }
+
+fail:
+       e->pos = pos;
        return 0;
 }
 
 static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
 {
+       void *pos = e->pos;
+
        if (unpack_nameX(e, AA_U64, name)) {
                if (!inbounds(e, sizeof(u64)))
-                       return 0;
+                       goto fail;
                if (data)
                        *data = le64_to_cpu(get_unaligned((__le64 *) e->pos));
                e->pos += sizeof(u64);
                return 1;
        }
+
+fail:
+       e->pos = pos;
        return 0;
 }
 
 static size_t unpack_array(struct aa_ext *e, const char *name)
 {
+       void *pos = e->pos;
+
        if (unpack_nameX(e, AA_ARRAY, name)) {
                int size;
                if (!inbounds(e, sizeof(u16)))
-                       return 0;
+                       goto fail;
                size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos));
                e->pos += sizeof(u16);
                return size;
        }
+
+fail:
+       e->pos = pos;
        return 0;
 }
 
 static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
 {
+       void *pos = e->pos;
+
        if (unpack_nameX(e, AA_BLOB, name)) {
                u32 size;
                if (!inbounds(e, sizeof(u32)))
-                       return 0;
+                       goto fail;
                size = le32_to_cpu(get_unaligned((__le32 *) e->pos));
                e->pos += sizeof(u32);
                if (inbounds(e, (size_t) size)) {
@@ -328,6 +363,9 @@ static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
                        return size;
                }
        }
+
+fail:
+       e->pos = pos;
        return 0;
 }
 
@@ -344,9 +382,10 @@ static int unpack_str(struct aa_ext *e, const char **string, const char *name)
                        if (src_str[size - 1] != 0)
                                goto fail;
                        *string = src_str;
+
+                       return size;
                }
        }
-       return size;
 
 fail:
        e->pos = pos;
@@ -584,7 +623,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
        struct aa_profile *profile = NULL;
        const char *tmpname, *tmpns = NULL, *name = NULL;
        const char *info = "failed to unpack profile";
-       size_t ns_len;
+       size_t size = 0, ns_len;
        struct rhashtable_params params = { 0 };
        char *key = NULL;
        struct aa_data *data;
@@ -717,6 +756,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                goto fail;
        }
 
+       size = unpack_array(e, "net_allowed_af");
+       if (size) {
+
+               for (i = 0; i < size; i++) {
+                       /* discard extraneous rules that this kernel will
+                        * never request
+                        */
+                       if (i >= AF_MAX) {
+                               u16 tmp;
+
+                               if (!unpack_u16(e, &tmp, NULL) ||
+                                   !unpack_u16(e, &tmp, NULL) ||
+                                   !unpack_u16(e, &tmp, NULL))
+                                       goto fail;
+                               continue;
+                       }
+                       if (!unpack_u16(e, &profile->net.allow[i], NULL))
+                               goto fail;
+                       if (!unpack_u16(e, &profile->net.audit[i], NULL))
+                               goto fail;
+                       if (!unpack_u16(e, &profile->net.quiet[i], NULL))
+                               goto fail;
+               }
+               if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+                       goto fail;
+       }
+       if (VERSION_LT(e->version, v7)) {
+               /* pre v7 policy always allowed these */
+               profile->net.allow[AF_UNIX] = 0xffff;
+               profile->net.allow[AF_NETLINK] = 0xffff;
+       }
+
        if (unpack_nameX(e, AA_STRUCT, "policydb")) {
                /* generic policy dfa - optional and may be NULL */
                info = "failed to unpack policydb";