• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org>
4  */
5 
6 /*\
7  * [Description]
8  *
9  * Basic finit_module() failure tests.
10  *
11  * [Algorithm]
12  *
13  * Tests various failure scenarios for finit_module().
14  */
15 
16 #include <linux/capability.h>
17 #include <errno.h>
18 #include "lapi/init_module.h"
19 #include "tst_module.h"
20 #include "tst_capability.h"
21 
22 #define MODULE_NAME	"finit_module.ko"
23 #define TEST_DIR	"test_dir"
24 
25 static char *mod_path;
26 
27 static int fd, fd_zero, fd_invalid = -1, fd_dir;
28 static int kernel_lockdown;
29 
30 static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE);
31 static struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE);
32 
33 struct tcase {
34 	const char *name;
35 	int *fd;
36 	const char *param;
37 	int open_flags;
38 	int flags;
39 	int cap;
40 	int exp_errno;
41 	int skip_in_lockdown;
42 	void (*fix_errno)(struct tcase *tc);
43 };
44 
bad_fd_setup(struct tcase * tc)45 static void bad_fd_setup(struct tcase *tc)
46 {
47 	if (tst_kvercmp(4, 6, 0) < 0)
48 		tc->exp_errno = ENOEXEC;
49 	else
50 		tc->exp_errno = EBADF;
51 }
52 
dir_setup(struct tcase * tc)53 static void dir_setup(struct tcase *tc)
54 {
55 	if (tst_kvercmp(4, 6, 0) < 0)
56 		tc->exp_errno = EISDIR;
57 	else
58 		tc->exp_errno = EINVAL;
59 }
60 
61 static struct tcase tcases[] = {
62 	{"invalid-fd", &fd_invalid, "", O_RDONLY | O_CLOEXEC, 0, 0, 0, 0,
63 		bad_fd_setup},
64 	{"zero-fd", &fd_zero, "", O_RDONLY | O_CLOEXEC, 0, 0, EINVAL, 0, NULL},
65 	{"null-param", &fd, NULL, O_RDONLY | O_CLOEXEC, 0, 0, EFAULT, 1, NULL},
66 	{"invalid-param", &fd, "status=invalid", O_RDONLY | O_CLOEXEC, 0, 0,
67 		EINVAL, 1, NULL},
68 	{"invalid-flags", &fd, "", O_RDONLY | O_CLOEXEC, -1, 0, EINVAL, 0,
69 		NULL},
70 	{"no-perm", &fd, "", O_RDONLY | O_CLOEXEC, 0, 1, EPERM, 0, NULL},
71 	{"module-exists", &fd, "", O_RDONLY | O_CLOEXEC, 0, 0, EEXIST, 1,
72 		NULL},
73 	{"file-not-readable", &fd, "", O_WRONLY | O_CLOEXEC, 0, 0, EBADF, 0,
74 		NULL},
75 	{"file-readwrite", &fd, "", O_RDWR | O_CLOEXEC, 0, 0, ETXTBSY, 0,
76 		NULL},
77 	{"directory", &fd_dir, "", O_RDONLY | O_CLOEXEC, 0, 0, 0, 0, dir_setup},
78 };
79 
setup(void)80 static void setup(void)
81 {
82 	unsigned long int i;
83 
84 	finit_module_supported_by_kernel();
85 
86 	tst_module_exists(MODULE_NAME, &mod_path);
87 
88 	kernel_lockdown = tst_lockdown_enabled();
89 	SAFE_MKDIR(TEST_DIR, 0700);
90 	fd_dir = SAFE_OPEN(TEST_DIR, O_DIRECTORY);
91 
92 	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
93 		if (tcases[i].fix_errno)
94 			tcases[i].fix_errno(&tcases[i]);
95 	}
96 }
97 
cleanup(void)98 static void cleanup(void)
99 {
100 	SAFE_CLOSE(fd_dir);
101 }
102 
run(unsigned int n)103 static void run(unsigned int n)
104 {
105 	struct tcase *tc = &tcases[n];
106 
107 	if (tc->skip_in_lockdown && kernel_lockdown) {
108 		tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name);
109 		return;
110 	}
111 
112 	fd = SAFE_OPEN(mod_path, tc->open_flags);
113 
114 	if (tc->cap)
115 		tst_cap_action(&cap_drop);
116 
117 	/* Insert module twice */
118 	if (tc->exp_errno == EEXIST)
119 		tst_module_load(MODULE_NAME, NULL);
120 
121 	TST_EXP_FAIL(finit_module(*tc->fd, tc->param, tc->flags), tc->exp_errno,
122 		     "TestName: %s", tc->name);
123 
124 	if (tc->exp_errno == EEXIST)
125 		tst_module_unload(MODULE_NAME);
126 
127 	if (!TST_PASS && !TST_RET)
128 		tst_module_unload(MODULE_NAME);
129 
130 	if (tc->cap)
131 		tst_cap_action(&cap_req);
132 
133 	SAFE_CLOSE(fd);
134 }
135 
136 static struct tst_test test = {
137 	.tags = (const struct tst_tag[]) {
138 		{"linux-git", "032146cda855"},
139 		{"linux-git", "39d637af5aa7"},
140 		{}
141 	},
142 	.test = run,
143 	.tcnt = ARRAY_SIZE(tcases),
144 	.setup = setup,
145 	.cleanup = cleanup,
146 	.needs_tmpdir = 1,
147 	.needs_root = 1,
148 };
149