1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*\
7f08c3bdfSopenharmony_ci * [Description]
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Basic init_module() failure tests.
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * [Algorithm]
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * Tests various failure scenarios for init_module().
14f08c3bdfSopenharmony_ci */
15f08c3bdfSopenharmony_ci
16f08c3bdfSopenharmony_ci#include <linux/capability.h>
17f08c3bdfSopenharmony_ci#include <errno.h>
18f08c3bdfSopenharmony_ci#include "lapi/init_module.h"
19f08c3bdfSopenharmony_ci#include "tst_module.h"
20f08c3bdfSopenharmony_ci#include "tst_capability.h"
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_ci#define MODULE_NAME	"init_module.ko"
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistatic unsigned long size, zero_size;
25f08c3bdfSopenharmony_cistatic int kernel_lockdown, secure_boot;
26f08c3bdfSopenharmony_cistatic void *buf, *faulty_buf, *null_buf;
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE);
29f08c3bdfSopenharmony_cistatic struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE);
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic struct tcase {
32f08c3bdfSopenharmony_ci	const char *name;
33f08c3bdfSopenharmony_ci	void **buf;
34f08c3bdfSopenharmony_ci	unsigned long *size;
35f08c3bdfSopenharmony_ci	const char *param;
36f08c3bdfSopenharmony_ci	int cap;
37f08c3bdfSopenharmony_ci	int skip_in_lockdown;
38f08c3bdfSopenharmony_ci	int exp_errno;
39f08c3bdfSopenharmony_ci} tcases[] = {
40f08c3bdfSopenharmony_ci	{"NULL-buffer", &null_buf, &size, "", 0, 0, EFAULT},
41f08c3bdfSopenharmony_ci	{"faulty-buffer", &faulty_buf, &size, "", 0, 0, EFAULT},
42f08c3bdfSopenharmony_ci	{"null-param", &buf, &size, NULL, 0, 1, EFAULT},
43f08c3bdfSopenharmony_ci	{"zero-size", &buf, &zero_size, "", 0, 0, ENOEXEC},
44f08c3bdfSopenharmony_ci	{"invalid_param", &buf, &size, "status=invalid", 0, 1, EINVAL},
45f08c3bdfSopenharmony_ci	{"no-perm", &buf, &size, "", 1, 0, EPERM},
46f08c3bdfSopenharmony_ci	{"module-exists", &buf, &size, "", 0, 1, EEXIST},
47f08c3bdfSopenharmony_ci};
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_cistatic void setup(void)
50f08c3bdfSopenharmony_ci{
51f08c3bdfSopenharmony_ci	struct stat sb;
52f08c3bdfSopenharmony_ci	int fd;
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci	tst_module_exists(MODULE_NAME, NULL);
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	kernel_lockdown = tst_lockdown_enabled() > 0;
57f08c3bdfSopenharmony_ci	secure_boot = tst_secureboot_enabled() > 0;
58f08c3bdfSopenharmony_ci	fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC);
59f08c3bdfSopenharmony_ci	SAFE_FSTAT(fd, &sb);
60f08c3bdfSopenharmony_ci	size = sb.st_size;
61f08c3bdfSopenharmony_ci	buf = SAFE_MMAP(0, size, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
62f08c3bdfSopenharmony_ci	SAFE_CLOSE(fd);
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	faulty_buf = tst_get_bad_addr(NULL);
65f08c3bdfSopenharmony_ci}
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_cistatic void run(unsigned int n)
68f08c3bdfSopenharmony_ci{
69f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) {
72f08c3bdfSopenharmony_ci		tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name);
73f08c3bdfSopenharmony_ci		return;
74f08c3bdfSopenharmony_ci	}
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	if (tc->cap)
77f08c3bdfSopenharmony_ci		tst_cap_action(&cap_drop);
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_ci	/* Insert module twice */
80f08c3bdfSopenharmony_ci	if (tc->exp_errno == EEXIST)
81f08c3bdfSopenharmony_ci		tst_module_load(MODULE_NAME, NULL);
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	TST_EXP_FAIL(init_module(*tc->buf, *tc->size, tc->param),
84f08c3bdfSopenharmony_ci		tc->exp_errno, "TestName: %s", tc->name);
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	if (tc->exp_errno == EEXIST)
87f08c3bdfSopenharmony_ci		tst_module_unload(MODULE_NAME);
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	if (!TST_PASS && !TST_RET)
90f08c3bdfSopenharmony_ci		tst_module_unload(MODULE_NAME);
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci	if (tc->cap)
93f08c3bdfSopenharmony_ci		tst_cap_action(&cap_req);
94f08c3bdfSopenharmony_ci}
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_cistatic void cleanup(void)
97f08c3bdfSopenharmony_ci{
98f08c3bdfSopenharmony_ci	munmap(buf, size);
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_cistatic struct tst_test test = {
102f08c3bdfSopenharmony_ci	.test = run,
103f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
104f08c3bdfSopenharmony_ci	.setup = setup,
105f08c3bdfSopenharmony_ci	.cleanup = cleanup,
106f08c3bdfSopenharmony_ci	.needs_root = 1,
107f08c3bdfSopenharmony_ci};
108