root/tools/testing/selftests/lsm/lsm_list_modules_test.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Linux Security Module infrastructure tests
 * Tests for the lsm_list_modules system call
 *
 * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com>
 */

#define _GNU_SOURCE
#include <linux/lsm.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include "kselftest_harness.h"
#include "common.h"

TEST(size_null_lsm_list_modules)
{
        const long page_size = sysconf(_SC_PAGESIZE);
        __u64 *syscall_lsms = calloc(page_size, 1);

        ASSERT_NE(NULL, syscall_lsms);
        errno = 0;
        ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, NULL, 0));
        ASSERT_EQ(EFAULT, errno);

        free(syscall_lsms);
}

TEST(ids_null_lsm_list_modules)
{
        const long page_size = sysconf(_SC_PAGESIZE);
        __u32 size = page_size;

        errno = 0;
        ASSERT_EQ(-1, lsm_list_modules(NULL, &size, 0));
        ASSERT_EQ(EFAULT, errno);
        ASSERT_NE(1, size);
}

TEST(size_too_small_lsm_list_modules)
{
        const long page_size = sysconf(_SC_PAGESIZE);
        __u64 *syscall_lsms = calloc(page_size, 1);
        __u32 size = 1;

        ASSERT_NE(NULL, syscall_lsms);
        errno = 0;
        ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, &size, 0));
        ASSERT_EQ(E2BIG, errno);
        ASSERT_NE(1, size);

        free(syscall_lsms);
}

TEST(flags_set_lsm_list_modules)
{
        const long page_size = sysconf(_SC_PAGESIZE);
        __u64 *syscall_lsms = calloc(page_size, 1);
        __u32 size = page_size;

        ASSERT_NE(NULL, syscall_lsms);
        errno = 0;
        ASSERT_EQ(-1, lsm_list_modules(syscall_lsms, &size, 7));
        ASSERT_EQ(EINVAL, errno);
        ASSERT_EQ(page_size, size);

        free(syscall_lsms);
}

TEST(correct_lsm_list_modules)
{
        const long page_size = sysconf(_SC_PAGESIZE);
        __u32 size = page_size;
        __u64 *syscall_lsms = calloc(page_size, 1);
        char *sysfs_lsms = calloc(page_size, 1);
        char *name;
        char *cp;
        int count;
        int i;

        ASSERT_NE(NULL, sysfs_lsms);
        ASSERT_NE(NULL, syscall_lsms);
        ASSERT_EQ(0, read_sysfs_lsms(sysfs_lsms, page_size));

        count = lsm_list_modules(syscall_lsms, &size, 0);
        ASSERT_LE(1, count);
        cp = sysfs_lsms;
        for (i = 0; i < count; i++) {
                switch (syscall_lsms[i]) {
                case LSM_ID_CAPABILITY:
                        name = "capability";
                        break;
                case LSM_ID_SELINUX:
                        name = "selinux";
                        break;
                case LSM_ID_SMACK:
                        name = "smack";
                        break;
                case LSM_ID_TOMOYO:
                        name = "tomoyo";
                        break;
                case LSM_ID_APPARMOR:
                        name = "apparmor";
                        break;
                case LSM_ID_YAMA:
                        name = "yama";
                        break;
                case LSM_ID_LOADPIN:
                        name = "loadpin";
                        break;
                case LSM_ID_SAFESETID:
                        name = "safesetid";
                        break;
                case LSM_ID_LOCKDOWN:
                        name = "lockdown";
                        break;
                case LSM_ID_BPF:
                        name = "bpf";
                        break;
                case LSM_ID_LANDLOCK:
                        name = "landlock";
                        break;
                case LSM_ID_IMA:
                        name = "ima";
                        break;
                case LSM_ID_EVM:
                        name = "evm";
                        break;
                case LSM_ID_IPE:
                        name = "ipe";
                        break;
                default:
                        name = "INVALID";
                        break;
                }
                ASSERT_EQ(0, strncmp(cp, name, strlen(name)));
                cp += strlen(name) + 1;
        }

        free(sysfs_lsms);
        free(syscall_lsms);
}

TEST_HARNESS_MAIN