root/security/apparmor/policy_unpack_test.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * KUnit tests for AppArmor's policy unpack.
 */

#include <kunit/test.h>
#include <kunit/visibility.h>

#include "include/policy.h"
#include "include/policy_unpack.h"

#include <linux/unaligned.h>

#define TEST_STRING_NAME "TEST_STRING"
#define TEST_STRING_DATA "testing"
#define TEST_STRING_BUF_OFFSET \
        (3 + strlen(TEST_STRING_NAME) + 1)

#define TEST_U32_NAME "U32_TEST"
#define TEST_U32_DATA ((u32)0x01020304)
#define TEST_NAMED_U32_BUF_OFFSET \
        (TEST_STRING_BUF_OFFSET + 3 + strlen(TEST_STRING_DATA) + 1)
#define TEST_U32_BUF_OFFSET \
        (TEST_NAMED_U32_BUF_OFFSET + 3 + strlen(TEST_U32_NAME) + 1)

#define TEST_U16_OFFSET (TEST_U32_BUF_OFFSET + 3)
#define TEST_U16_DATA ((u16)(TEST_U32_DATA >> 16))

#define TEST_U64_NAME "U64_TEST"
#define TEST_U64_DATA ((u64)0x0102030405060708)
#define TEST_NAMED_U64_BUF_OFFSET (TEST_U32_BUF_OFFSET + sizeof(u32) + 1)
#define TEST_U64_BUF_OFFSET \
        (TEST_NAMED_U64_BUF_OFFSET + 3 + strlen(TEST_U64_NAME) + 1)

#define TEST_BLOB_NAME "BLOB_TEST"
#define TEST_BLOB_DATA "\xde\xad\x00\xbe\xef"
#define TEST_BLOB_DATA_SIZE (ARRAY_SIZE(TEST_BLOB_DATA))
#define TEST_NAMED_BLOB_BUF_OFFSET (TEST_U64_BUF_OFFSET + sizeof(u64) + 1)
#define TEST_BLOB_BUF_OFFSET \
        (TEST_NAMED_BLOB_BUF_OFFSET + 3 + strlen(TEST_BLOB_NAME) + 1)

#define TEST_ARRAY_NAME "ARRAY_TEST"
#define TEST_ARRAY_SIZE 16
#define TEST_NAMED_ARRAY_BUF_OFFSET \
        (TEST_BLOB_BUF_OFFSET + 5 + TEST_BLOB_DATA_SIZE)
#define TEST_ARRAY_BUF_OFFSET \
        (TEST_NAMED_ARRAY_BUF_OFFSET + 3 + strlen(TEST_ARRAY_NAME) + 1)

MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");

struct policy_unpack_fixture {
        struct aa_ext *e;
        size_t e_size;
};

static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
                                          struct kunit *test, size_t buf_size)
{
        char *buf;
        struct aa_ext *e;

        buf = kunit_kzalloc(test, buf_size, GFP_USER);
        KUNIT_EXPECT_NOT_ERR_OR_NULL(test, buf);

        e = kunit_kmalloc(test, sizeof(*e), GFP_USER);
        KUNIT_EXPECT_NOT_ERR_OR_NULL(test, e);

        e->start = buf;
        e->end = e->start + buf_size;
        e->pos = e->start;

        *buf = AA_NAME;
        *(buf + 1) = strlen(TEST_STRING_NAME) + 1;
        strscpy(buf + 3, TEST_STRING_NAME, e->end - (void *)(buf + 3));

        buf = e->start + TEST_STRING_BUF_OFFSET;
        *buf = AA_STRING;
        *(buf + 1) = strlen(TEST_STRING_DATA) + 1;
        strscpy(buf + 3, TEST_STRING_DATA, e->end - (void *)(buf + 3));
        buf = e->start + TEST_NAMED_U32_BUF_OFFSET;
        *buf = AA_NAME;
        *(buf + 1) = strlen(TEST_U32_NAME) + 1;
        strscpy(buf + 3, TEST_U32_NAME, e->end - (void *)(buf + 3));
        *(buf + 3 + strlen(TEST_U32_NAME) + 1) = AA_U32;
        put_unaligned_le32(TEST_U32_DATA, buf + 3 + strlen(TEST_U32_NAME) + 2);

        buf = e->start + TEST_NAMED_U64_BUF_OFFSET;
        *buf = AA_NAME;
        *(buf + 1) = strlen(TEST_U64_NAME) + 1;
        strscpy(buf + 3, TEST_U64_NAME, e->end - (void *)(buf + 3));
        *(buf + 3 + strlen(TEST_U64_NAME) + 1) = AA_U64;
        *((__le64 *)(buf + 3 + strlen(TEST_U64_NAME) + 2)) = cpu_to_le64(TEST_U64_DATA);

        buf = e->start + TEST_NAMED_BLOB_BUF_OFFSET;
        *buf = AA_NAME;
        *(buf + 1) = strlen(TEST_BLOB_NAME) + 1;
        strscpy(buf + 3, TEST_BLOB_NAME, e->end - (void *)(buf + 3));
        *(buf + 3 + strlen(TEST_BLOB_NAME) + 1) = AA_BLOB;
        *(buf + 3 + strlen(TEST_BLOB_NAME) + 2) = TEST_BLOB_DATA_SIZE;
        memcpy(buf + 3 + strlen(TEST_BLOB_NAME) + 6,
                TEST_BLOB_DATA, TEST_BLOB_DATA_SIZE);

        buf = e->start + TEST_NAMED_ARRAY_BUF_OFFSET;
        *buf = AA_NAME;
        *(buf + 1) = strlen(TEST_ARRAY_NAME) + 1;
        strscpy(buf + 3, TEST_ARRAY_NAME, e->end - (void *)(buf + 3));
        *(buf + 3 + strlen(TEST_ARRAY_NAME) + 1) = AA_ARRAY;
        put_unaligned_le16(TEST_ARRAY_SIZE, buf + 3 + strlen(TEST_ARRAY_NAME) + 2);

        return e;
}

static int policy_unpack_test_init(struct kunit *test)
{
        size_t e_size = TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1;
        struct policy_unpack_fixture *puf;

        puf = kunit_kmalloc(test, sizeof(*puf), GFP_USER);
        KUNIT_EXPECT_NOT_ERR_OR_NULL(test, puf);

        puf->e_size = e_size;
        puf->e = build_aa_ext_struct(puf, test, e_size);

        test->priv = puf;
        return 0;
}

static void policy_unpack_test_inbounds_when_inbounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;

        KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, 0));
        KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, puf->e_size / 2));
        KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, puf->e_size));
}

static void policy_unpack_test_inbounds_when_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;

        KUNIT_EXPECT_FALSE(test, aa_inbounds(puf->e, puf->e_size + 1));
}

static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        u16 array_size = 0;

        puf->e->pos += TEST_ARRAY_BUF_OFFSET;

        KUNIT_EXPECT_TRUE(test, aa_unpack_array(puf->e, NULL, &array_size));
        KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1);
}

static void policy_unpack_test_unpack_array_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_ARRAY_NAME;
        u16 array_size = 0;

        puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET;

        KUNIT_EXPECT_TRUE(test, aa_unpack_array(puf->e, name, &array_size));
        KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16) + 1);
}

static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_ARRAY_NAME;
        u16 array_size;

        puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET;
        puf->e->end = puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16);

        KUNIT_EXPECT_FALSE(test, aa_unpack_array(puf->e, name, &array_size));
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                puf->e->start + TEST_NAMED_ARRAY_BUF_OFFSET);
}

static void policy_unpack_test_unpack_blob_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *blob = NULL;
        size_t size;

        puf->e->pos += TEST_BLOB_BUF_OFFSET;
        size = aa_unpack_blob(puf->e, &blob, NULL);

        KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE);
        KUNIT_EXPECT_TRUE(test,
                memcmp(blob, TEST_BLOB_DATA, TEST_BLOB_DATA_SIZE) == 0);
}

static void policy_unpack_test_unpack_blob_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *blob = NULL;
        size_t size;

        puf->e->pos += TEST_NAMED_BLOB_BUF_OFFSET;
        size = aa_unpack_blob(puf->e, &blob, TEST_BLOB_NAME);

        KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE);
        KUNIT_EXPECT_TRUE(test,
                memcmp(blob, TEST_BLOB_DATA, TEST_BLOB_DATA_SIZE) == 0);
}

static void policy_unpack_test_unpack_blob_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *blob = NULL;
        void *start;
        int size;

        puf->e->pos += TEST_NAMED_BLOB_BUF_OFFSET;
        start = puf->e->pos;
        puf->e->end = puf->e->start + TEST_BLOB_BUF_OFFSET
                + TEST_BLOB_DATA_SIZE - 1;

        size = aa_unpack_blob(puf->e, &blob, TEST_BLOB_NAME);

        KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
}

static void policy_unpack_test_unpack_str_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char *string = NULL;
        size_t size;

        puf->e->pos += TEST_STRING_BUF_OFFSET;
        size = aa_unpack_str(puf->e, &string, NULL);

        KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
        KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
}

static void policy_unpack_test_unpack_str_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char *string = NULL;
        size_t size;

        size = aa_unpack_str(puf->e, &string, TEST_STRING_NAME);

        KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
        KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
}

static void policy_unpack_test_unpack_str_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char *string = NULL;
        void *start = puf->e->pos;
        int size;

        puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET
                + strlen(TEST_STRING_DATA) - 1;

        size = aa_unpack_str(puf->e, &string, TEST_STRING_NAME);

        KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
}

static void policy_unpack_test_unpack_strdup_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *string = NULL;
        size_t size;

        puf->e->pos += TEST_STRING_BUF_OFFSET;
        size = aa_unpack_strdup(puf->e, &string, NULL);

        KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
        KUNIT_EXPECT_FALSE(test,
                           ((uintptr_t)puf->e->start <= (uintptr_t)string)
                           && ((uintptr_t)string <= (uintptr_t)puf->e->end));
        KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);

        kfree(string);
}

static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *string = NULL;
        size_t size;

        size = aa_unpack_strdup(puf->e, &string, TEST_STRING_NAME);

        KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
        KUNIT_EXPECT_FALSE(test,
                           ((uintptr_t)puf->e->start <= (uintptr_t)string)
                           && ((uintptr_t)string <= (uintptr_t)puf->e->end));
        KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);

        kfree(string);
}

static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        void *start = puf->e->pos;
        char *string = NULL;
        int size;

        puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET
                + strlen(TEST_STRING_DATA) - 1;

        size = aa_unpack_strdup(puf->e, &string, TEST_STRING_NAME);

        KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_NULL(test, string);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);

        kfree(string);
}

static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success;

        puf->e->pos += TEST_U32_BUF_OFFSET;

        success = aa_unpack_nameX(puf->e, AA_U32, NULL);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                            puf->e->start + TEST_U32_BUF_OFFSET + 1);
}

static void policy_unpack_test_unpack_nameX_with_wrong_code(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success;

        puf->e->pos += TEST_U32_BUF_OFFSET;

        success = aa_unpack_nameX(puf->e, AA_BLOB, NULL);

        KUNIT_EXPECT_FALSE(test, success);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                            puf->e->start + TEST_U32_BUF_OFFSET);
}

static void policy_unpack_test_unpack_nameX_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U32_NAME;
        bool success;

        puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;

        success = aa_unpack_nameX(puf->e, AA_U32, name);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                            puf->e->start + TEST_U32_BUF_OFFSET + 1);
}

static void policy_unpack_test_unpack_nameX_with_wrong_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        static const char name[] = "12345678";
        bool success;

        puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;

        success = aa_unpack_nameX(puf->e, AA_U32, name);

        KUNIT_EXPECT_FALSE(test, success);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                            puf->e->start + TEST_NAMED_U32_BUF_OFFSET);
}

static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *chunk = NULL;
        size_t size;

        puf->e->pos += TEST_U16_OFFSET;
        /*
         * WARNING: For unit testing purposes, we're pushing puf->e->end past
         * the end of the allocated memory. Doing anything other than comparing
         * memory addresses is dangerous.
         */
        puf->e->end += TEST_U16_DATA;

        size = aa_unpack_u16_chunk(puf->e, &chunk);

        KUNIT_EXPECT_PTR_EQ(test, chunk,
                            puf->e->start + TEST_U16_OFFSET + 2);
        KUNIT_EXPECT_EQ(test, size, TEST_U16_DATA);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (chunk + TEST_U16_DATA));
}

static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1(
                struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *chunk = NULL;
        size_t size;

        puf->e->pos = puf->e->end - 1;

        size = aa_unpack_u16_chunk(puf->e, &chunk);

        KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_NULL(test, chunk);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->end - 1);
}

static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2(
                struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        char *chunk = NULL;
        size_t size;

        puf->e->pos += TEST_U16_OFFSET;
        /*
         * WARNING: For unit testing purposes, we're pushing puf->e->end past
         * the end of the allocated memory. Doing anything other than comparing
         * memory addresses is dangerous.
         */
        puf->e->end = puf->e->pos + TEST_U16_DATA - 1;

        size = aa_unpack_u16_chunk(puf->e, &chunk);

        KUNIT_EXPECT_EQ(test, size, 0);
        KUNIT_EXPECT_NULL(test, chunk);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_U16_OFFSET);
}

static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success;
        u32 data = 0;

        puf->e->pos += TEST_U32_BUF_OFFSET;

        success = aa_unpack_u32(puf->e, &data, NULL);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                        puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32) + 1);
}

static void policy_unpack_test_unpack_u32_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U32_NAME;
        bool success;
        u32 data = 0;

        puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;

        success = aa_unpack_u32(puf->e, &data, name);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                        puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32) + 1);
}

static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U32_NAME;
        bool success;
        u32 data = 0;

        puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
        puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32);

        success = aa_unpack_u32(puf->e, &data, name);

        KUNIT_EXPECT_FALSE(test, success);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                        puf->e->start + TEST_NAMED_U32_BUF_OFFSET);
}

static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success;
        u64 data = 0;

        puf->e->pos += TEST_U64_BUF_OFFSET;

        success = aa_unpack_u64(puf->e, &data, NULL);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                        puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64) + 1);
}

static void policy_unpack_test_unpack_u64_with_name(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U64_NAME;
        bool success;
        u64 data = 0;

        puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;

        success = aa_unpack_u64(puf->e, &data, name);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                        puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64) + 1);
}

static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        const char name[] = TEST_U64_NAME;
        bool success;
        u64 data = 0;

        puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
        puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64);

        success = aa_unpack_u64(puf->e, &data, name);

        KUNIT_EXPECT_FALSE(test, success);
        KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
                        puf->e->start + TEST_NAMED_U64_BUF_OFFSET);
}

static void policy_unpack_test_unpack_X_code_match(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success = aa_unpack_X(puf->e, AA_NAME);

        KUNIT_EXPECT_TRUE(test, success);
        KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start + 1);
}

static void policy_unpack_test_unpack_X_code_mismatch(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success = aa_unpack_X(puf->e, AA_STRING);

        KUNIT_EXPECT_FALSE(test, success);
        KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start);
}

static void policy_unpack_test_unpack_X_out_of_bounds(struct kunit *test)
{
        struct policy_unpack_fixture *puf = test->priv;
        bool success;

        puf->e->pos = puf->e->end;
        success = aa_unpack_X(puf->e, AA_NAME);

        KUNIT_EXPECT_FALSE(test, success);
}

static struct kunit_case apparmor_policy_unpack_test_cases[] = {
        KUNIT_CASE(policy_unpack_test_inbounds_when_inbounds),
        KUNIT_CASE(policy_unpack_test_inbounds_when_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_array_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_array_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_array_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_blob_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_blob_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_blob_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_nameX_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_nameX_with_wrong_code),
        KUNIT_CASE(policy_unpack_test_unpack_nameX_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_nameX_with_wrong_name),
        KUNIT_CASE(policy_unpack_test_unpack_str_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_str_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_str_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_strdup_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_strdup_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_strdup_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_u16_chunk_basic),
        KUNIT_CASE(policy_unpack_test_unpack_u16_chunk_out_of_bounds_1),
        KUNIT_CASE(policy_unpack_test_unpack_u16_chunk_out_of_bounds_2),
        KUNIT_CASE(policy_unpack_test_unpack_u32_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_u32_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_u32_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_u64_with_null_name),
        KUNIT_CASE(policy_unpack_test_unpack_u64_with_name),
        KUNIT_CASE(policy_unpack_test_unpack_u64_out_of_bounds),
        KUNIT_CASE(policy_unpack_test_unpack_X_code_match),
        KUNIT_CASE(policy_unpack_test_unpack_X_code_mismatch),
        KUNIT_CASE(policy_unpack_test_unpack_X_out_of_bounds),
        {},
};

static struct kunit_suite apparmor_policy_unpack_test_module = {
        .name = "apparmor_policy_unpack",
        .init = policy_unpack_test_init,
        .test_cases = apparmor_policy_unpack_test_cases,
};

kunit_test_suite(apparmor_policy_unpack_test_module);

MODULE_DESCRIPTION("KUnit tests for AppArmor's policy unpack");
MODULE_LICENSE("GPL");