diff mbox series

[v2,6/7] Add lsm_list_modules02 test

Message ID 20250110-lsm-v2-6-bd38035f86bc@suse.com
State Superseded
Headers show
Series LSM testing suite | expand

Commit Message

Andrea Cervesato Jan. 10, 2025, 12:55 p.m. UTC
From: Andrea Cervesato <andrea.cervesato@suse.com>

Verify that lsm_list_modules syscall is correctly recognizing LSM(s)
enabled inside the system.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 runtest/syscalls                                   |   1 +
 testcases/kernel/syscalls/lsm/.gitignore           |   1 +
 testcases/kernel/syscalls/lsm/lsm_list_modules02.c | 138 +++++++++++++++++++++
 3 files changed, 140 insertions(+)

Comments

Cyril Hrubis March 4, 2025, 1:24 p.m. UTC | #1
Hi!
> +#include "lsm_common.h"
> +
> +#define MAX_LSM_NUM 32
> +
> +static char lsm_names[MAX_LSM_NUM][BUFSIZ];
> +static size_t lsm_names_count;
> +static uint32_t page_size;
> +static uint64_t *ids;
> +static uint32_t *size;
> +
> +static void run(void)
> +{
> +	uint32_t lsm_num;
> +	size_t count;
> +
> +	memset(ids, 0, sizeof(uint64_t) * MAX_LSM_NUM);
> +	*size = page_size;
> +
> +	lsm_num = TST_EXP_POSITIVE(lsm_list_modules(ids, size, 0));

If we want to pass the size as page_size here the buffer passed to the
syscall would have to be page_size in size. The whole point of passing
the size here is to tell the kernel the size of the buffer it can use
and it's a pointer because kernel will return the size of the buffer it
used back.

> +
> +	TST_EXP_EQ_LI(lsm_num, lsm_names_count);
> +	TST_EXP_EQ_LI(*size, lsm_num * sizeof(uint64_t));
> +
> +	for (uint32_t i = 0; i < lsm_num; i++) {
> +		char *name = NULL;
> +
> +		switch (ids[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:
> +			break;
> +		}

I guess that it may be also a good idea to have an array where we would
record which LSM we have seen in the buffer to make sure that we didn't
get any of them twice.

I suppose that we can turn the lsm_names into a structure and add
counters there with:


struct lsm_name {
	int cnt;
	char name[MAX_LSM_NAME];
};

struct lsm_name lsm_names[MAX_LSM_NUM];

> +		if (!name)
> +			tst_brk(TBROK, "Unsupported LSM: %lu", ids[i]);
> +
> +		for (count = 0; count < lsm_names_count; count++) {
> +			if (!strcmp(name, lsm_names[count])) {
> +				tst_res(TPASS, "'%s' is enabled", name);

And then we can (assuming we zero the counters at the start of this
function) do:

				if (lsm_names[count].cnt)
					tst_res(TFAIL, "Duplicated LSM entry %s", lsm_names[count].name);

				lsm_names[count].cnt++;

> +				break;
> +			}
> +		}
> +
> +		if (count >= lsm_names_count)
> +			tst_res(TFAIL, "'%s' has not been found", name);
> +	}
> +}
> +
> +static void setup(void)
> +{
> +	int fd;
> +	char *ptr;
> +	char data[BUFSIZ];
> +
> +	memset(data, 0, BUFSIZ);
> +
> +	page_size = SAFE_SYSCONF(_SC_PAGESIZE);
> +	fd = SAFE_OPEN("/sys/kernel/security/lsm", O_RDONLY);
> +	SAFE_READ(0, fd, data, BUFSIZ);
> +	SAFE_CLOSE(fd);
> +
> +	ptr = strtok(data, ",");
> +
> +	while (ptr != NULL) {
> +		strcpy(lsm_names[lsm_names_count], ptr);
> +		ptr = strtok(NULL, ",");
> +		lsm_names_count++;
> +	}
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.min_kver = "6.8",
> +	.bufs = (struct tst_buffers []) {
> +		{&ids, .size = sizeof(uint64_t) * MAX_LSM_NUM},
> +		{&size, .size = sizeof(uint32_t)},
> +		{},
> +	},
> +};
> 
> -- 
> 2.43.0
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp
diff mbox series

Patch

diff --git a/runtest/syscalls b/runtest/syscalls
index ae1f430e3dcfebb5167990fcef45b1f3658f6dba..71c644b2da0e55df40ec753c5c31eeb9c474e146 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -760,6 +760,7 @@  lsm_get_self_attr01 lsm_get_self_attr01
 lsm_get_self_attr02 lsm_get_self_attr02
 lsm_get_self_attr03 lsm_get_self_attr03
 lsm_list_modules01 lsm_list_modules01
+lsm_list_modules02 lsm_list_modules02
 
 lstat01 lstat01
 lstat01_64 lstat01_64
diff --git a/testcases/kernel/syscalls/lsm/.gitignore b/testcases/kernel/syscalls/lsm/.gitignore
index 501d332549a84cceb9741346bdb8b83eb02467c5..766f81fd1c74a10001862f142c02ba251e666ef2 100644
--- a/testcases/kernel/syscalls/lsm/.gitignore
+++ b/testcases/kernel/syscalls/lsm/.gitignore
@@ -2,3 +2,4 @@  lsm_get_self_attr01
 lsm_get_self_attr02
 lsm_get_self_attr03
 lsm_list_modules01
+lsm_list_modules02
diff --git a/testcases/kernel/syscalls/lsm/lsm_list_modules02.c b/testcases/kernel/syscalls/lsm/lsm_list_modules02.c
new file mode 100644
index 0000000000000000000000000000000000000000..b286e6da9581e9ae1cb14f11409f3954568d3c7d
--- /dev/null
+++ b/testcases/kernel/syscalls/lsm/lsm_list_modules02.c
@@ -0,0 +1,138 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Verify that lsm_list_modules syscall is correctly recognizing LSM(s) enabled
+ * inside the system.
+ *
+ * [Algorithm]
+ *
+ * - read enabled LSM(s) inside /sys/kernel/security/lsm file
+ * - collect LSM IDs using lsm_list_modules syscall
+ * - compare the results, verifying that LSM(s) IDs are correct
+ */
+
+#include "lsm_common.h"
+
+#define MAX_LSM_NUM 32
+
+static char lsm_names[MAX_LSM_NUM][BUFSIZ];
+static size_t lsm_names_count;
+static uint32_t page_size;
+static uint64_t *ids;
+static uint32_t *size;
+
+static void run(void)
+{
+	uint32_t lsm_num;
+	size_t count;
+
+	memset(ids, 0, sizeof(uint64_t) * MAX_LSM_NUM);
+	*size = page_size;
+
+	lsm_num = TST_EXP_POSITIVE(lsm_list_modules(ids, size, 0));
+
+	TST_EXP_EQ_LI(lsm_num, lsm_names_count);
+	TST_EXP_EQ_LI(*size, lsm_num * sizeof(uint64_t));
+
+	for (uint32_t i = 0; i < lsm_num; i++) {
+		char *name = NULL;
+
+		switch (ids[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:
+			break;
+		}
+
+		if (!name)
+			tst_brk(TBROK, "Unsupported LSM: %lu", ids[i]);
+
+		for (count = 0; count < lsm_names_count; count++) {
+			if (!strcmp(name, lsm_names[count])) {
+				tst_res(TPASS, "'%s' is enabled", name);
+				break;
+			}
+		}
+
+		if (count >= lsm_names_count)
+			tst_res(TFAIL, "'%s' has not been found", name);
+	}
+}
+
+static void setup(void)
+{
+	int fd;
+	char *ptr;
+	char data[BUFSIZ];
+
+	memset(data, 0, BUFSIZ);
+
+	page_size = SAFE_SYSCONF(_SC_PAGESIZE);
+	fd = SAFE_OPEN("/sys/kernel/security/lsm", O_RDONLY);
+	SAFE_READ(0, fd, data, BUFSIZ);
+	SAFE_CLOSE(fd);
+
+	ptr = strtok(data, ",");
+
+	while (ptr != NULL) {
+		strcpy(lsm_names[lsm_names_count], ptr);
+		ptr = strtok(NULL, ",");
+		lsm_names_count++;
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.min_kver = "6.8",
+	.bufs = (struct tst_buffers []) {
+		{&ids, .size = sizeof(uint64_t) * MAX_LSM_NUM},
+		{&size, .size = sizeof(uint32_t)},
+		{},
+	},
+};