Merge tag 'pinctrl-v6.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-block.git] / tools / testing / selftests / mm / mdwe_test.c
CommitLineData
4cf1fe34
KC
1// SPDX-License-Identifier: GPL-2.0
2
3#ifdef __aarch64__
4#include <asm/hwcap.h>
5#endif
6
7#include <linux/mman.h>
8#include <linux/prctl.h>
9
80921623 10#define _GNU_SOURCE
4cf1fe34
KC
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/auxv.h>
14#include <sys/prctl.h>
15#include <sys/wait.h>
16#include <unistd.h>
17
18#include "../kselftest_harness.h"
19
20#ifndef __aarch64__
21# define PROT_BTI 0
22#endif
23
24TEST(prctl_flags)
25{
2dc539ac
FR
26 EXPECT_LT(prctl(PR_SET_MDWE, PR_MDWE_NO_INHERIT, 0L, 0L, 7L), 0);
27 EXPECT_EQ(errno, EINVAL);
28
4cf1fe34 29 EXPECT_LT(prctl(PR_SET_MDWE, 7L, 0L, 0L, 0L), 0);
c93d05a7 30 EXPECT_EQ(errno, EINVAL);
4cf1fe34 31 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 7L, 0L, 0L), 0);
c93d05a7 32 EXPECT_EQ(errno, EINVAL);
4cf1fe34 33 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 7L, 0L), 0);
c93d05a7 34 EXPECT_EQ(errno, EINVAL);
4cf1fe34 35 EXPECT_LT(prctl(PR_SET_MDWE, 0L, 0L, 0L, 7L), 0);
c93d05a7 36 EXPECT_EQ(errno, EINVAL);
4cf1fe34
KC
37
38 EXPECT_LT(prctl(PR_GET_MDWE, 7L, 0L, 0L, 0L), 0);
c93d05a7 39 EXPECT_EQ(errno, EINVAL);
4cf1fe34 40 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 7L, 0L, 0L), 0);
c93d05a7 41 EXPECT_EQ(errno, EINVAL);
4cf1fe34 42 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 7L, 0L), 0);
c93d05a7 43 EXPECT_EQ(errno, EINVAL);
4cf1fe34 44 EXPECT_LT(prctl(PR_GET_MDWE, 0L, 0L, 0L, 7L), 0);
c93d05a7 45 EXPECT_EQ(errno, EINVAL);
4cf1fe34
KC
46}
47
2dc539ac
FR
48FIXTURE(consecutive_prctl_flags) {};
49FIXTURE_SETUP(consecutive_prctl_flags) {}
50FIXTURE_TEARDOWN(consecutive_prctl_flags) {}
51
52FIXTURE_VARIANT(consecutive_prctl_flags)
53{
54 unsigned long first_flags;
55 unsigned long second_flags;
56 bool should_work;
57};
58
59FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_no_flags)
60{
61 .first_flags = 0,
62 .second_flags = 0,
63 .should_work = true,
64};
65
66FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_exec_gain)
67{
68 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN,
69 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN,
70 .should_work = true,
71};
72
73FIXTURE_VARIANT_ADD(consecutive_prctl_flags, can_keep_both_flags)
74{
75 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
76 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
77 .should_work = true,
78};
79
80FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_mdwe)
81{
82 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN,
83 .second_flags = 0,
84 .should_work = false,
85};
86
87FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_mdwe_no_inherit)
88{
89 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
90 .second_flags = 0,
91 .should_work = false,
92};
93
94FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_disable_no_inherit)
95{
96 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
97 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN,
98 .should_work = false,
99};
100
101FIXTURE_VARIANT_ADD(consecutive_prctl_flags, cant_enable_no_inherit)
102{
103 .first_flags = PR_MDWE_REFUSE_EXEC_GAIN,
104 .second_flags = PR_MDWE_REFUSE_EXEC_GAIN | PR_MDWE_NO_INHERIT,
105 .should_work = false,
106};
107
108TEST_F(consecutive_prctl_flags, two_prctls)
109{
110 int ret;
111
112 EXPECT_EQ(prctl(PR_SET_MDWE, variant->first_flags, 0L, 0L, 0L), 0);
113
114 ret = prctl(PR_SET_MDWE, variant->second_flags, 0L, 0L, 0L);
115 if (variant->should_work) {
116 EXPECT_EQ(ret, 0);
117
118 ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L);
119 ASSERT_EQ(ret, variant->second_flags);
120 } else {
121 EXPECT_NE(ret, 0);
122 ASSERT_EQ(errno, EPERM);
123 }
124}
125
4cf1fe34
KC
126FIXTURE(mdwe)
127{
128 void *p;
129 int flags;
130 size_t size;
131 pid_t pid;
132};
133
134FIXTURE_VARIANT(mdwe)
135{
136 bool enabled;
137 bool forked;
2dc539ac 138 bool inherit;
4cf1fe34
KC
139};
140
141FIXTURE_VARIANT_ADD(mdwe, stock)
142{
29d68b21 143 .enabled = false,
4cf1fe34 144 .forked = false,
2dc539ac 145 .inherit = false,
4cf1fe34
KC
146};
147
148FIXTURE_VARIANT_ADD(mdwe, enabled)
149{
29d68b21 150 .enabled = true,
4cf1fe34 151 .forked = false,
2dc539ac 152 .inherit = true,
4cf1fe34
KC
153};
154
2dc539ac 155FIXTURE_VARIANT_ADD(mdwe, inherited)
4cf1fe34 156{
29d68b21 157 .enabled = true,
4cf1fe34 158 .forked = true,
2dc539ac 159 .inherit = true,
4cf1fe34
KC
160};
161
2dc539ac
FR
162FIXTURE_VARIANT_ADD(mdwe, not_inherited)
163{
164 .enabled = true,
165 .forked = true,
166 .inherit = false,
167};
168
169static bool executable_map_should_fail(const FIXTURE_VARIANT(mdwe) *variant)
170{
171 return variant->enabled && (!variant->forked || variant->inherit);
172}
173
4cf1fe34
KC
174FIXTURE_SETUP(mdwe)
175{
2dc539ac 176 unsigned long mdwe_flags;
4cf1fe34
KC
177 int ret, status;
178
179 self->p = NULL;
180 self->flags = MAP_SHARED | MAP_ANONYMOUS;
181 self->size = getpagesize();
182
183 if (!variant->enabled)
184 return;
185
2dc539ac
FR
186 mdwe_flags = PR_MDWE_REFUSE_EXEC_GAIN;
187 if (!variant->inherit)
188 mdwe_flags |= PR_MDWE_NO_INHERIT;
189
190 ret = prctl(PR_SET_MDWE, mdwe_flags, 0L, 0L, 0L);
4cf1fe34
KC
191 ASSERT_EQ(ret, 0) {
192 TH_LOG("PR_SET_MDWE failed or unsupported");
193 }
194
195 ret = prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L);
2dc539ac 196 ASSERT_EQ(ret, mdwe_flags);
4cf1fe34
KC
197
198 if (variant->forked) {
199 self->pid = fork();
200 ASSERT_GE(self->pid, 0) {
201 TH_LOG("fork failed\n");
202 }
203
204 if (self->pid > 0) {
205 ret = waitpid(self->pid, &status, 0);
206 ASSERT_TRUE(WIFEXITED(status));
207 exit(WEXITSTATUS(status));
208 }
209 }
210}
211
212FIXTURE_TEARDOWN(mdwe)
213{
214 if (self->p && self->p != MAP_FAILED)
215 munmap(self->p, self->size);
216}
217
218TEST_F(mdwe, mmap_READ_EXEC)
219{
220 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0);
221 EXPECT_NE(self->p, MAP_FAILED);
222}
223
224TEST_F(mdwe, mmap_WRITE_EXEC)
225{
226 self->p = mmap(NULL, self->size, PROT_WRITE | PROT_EXEC, self->flags, 0, 0);
2dc539ac 227 if (executable_map_should_fail(variant)) {
4cf1fe34
KC
228 EXPECT_EQ(self->p, MAP_FAILED);
229 } else {
230 EXPECT_NE(self->p, MAP_FAILED);
231 }
232}
233
234TEST_F(mdwe, mprotect_stay_EXEC)
235{
236 int ret;
237
238 self->p = mmap(NULL, self->size, PROT_READ | PROT_EXEC, self->flags, 0, 0);
239 ASSERT_NE(self->p, MAP_FAILED);
240
241 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC);
242 EXPECT_EQ(ret, 0);
243}
244
245TEST_F(mdwe, mprotect_add_EXEC)
246{
247 int ret;
248
249 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0);
250 ASSERT_NE(self->p, MAP_FAILED);
251
252 ret = mprotect(self->p, self->size, PROT_READ | PROT_EXEC);
2dc539ac 253 if (executable_map_should_fail(variant)) {
4cf1fe34
KC
254 EXPECT_LT(ret, 0);
255 } else {
256 EXPECT_EQ(ret, 0);
257 }
258}
259
260TEST_F(mdwe, mprotect_WRITE_EXEC)
261{
262 int ret;
263
264 self->p = mmap(NULL, self->size, PROT_WRITE, self->flags, 0, 0);
265 ASSERT_NE(self->p, MAP_FAILED);
266
267 ret = mprotect(self->p, self->size, PROT_WRITE | PROT_EXEC);
2dc539ac 268 if (executable_map_should_fail(variant)) {
4cf1fe34
KC
269 EXPECT_LT(ret, 0);
270 } else {
271 EXPECT_EQ(ret, 0);
272 }
273}
274
275TEST_F(mdwe, mmap_FIXED)
276{
d035230e 277 void *p;
4cf1fe34 278
4cf1fe34
KC
279 self->p = mmap(NULL, self->size, PROT_READ, self->flags, 0, 0);
280 ASSERT_NE(self->p, MAP_FAILED);
281
a27e2e2d
FR
282 /* MAP_FIXED unmaps the existing page before mapping which is allowed */
283 p = mmap(self->p, self->size, PROT_READ | PROT_EXEC,
4cf1fe34 284 self->flags | MAP_FIXED, 0, 0);
a27e2e2d 285 EXPECT_EQ(p, self->p);
4cf1fe34
KC
286}
287
288TEST_F(mdwe, arm64_BTI)
289{
290 int ret;
291
292#ifdef __aarch64__
293 if (!(getauxval(AT_HWCAP2) & HWCAP2_BTI))
294#endif
295 SKIP(return, "HWCAP2_BTI not supported");
296
297 self->p = mmap(NULL, self->size, PROT_EXEC, self->flags, 0, 0);
298 ASSERT_NE(self->p, MAP_FAILED);
299
300 ret = mprotect(self->p, self->size, PROT_EXEC | PROT_BTI);
301 EXPECT_EQ(ret, 0);
302}
303
304TEST_HARNESS_MAIN