1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2023 ARM Limited.
4 */
5
6 #include <limits.h>
7 #include <stdbool.h>
8
9 #include <linux/prctl.h>
10
11 #include <sys/mman.h>
12 #include <asm/mman.h>
13 #include <linux/sched.h>
14
15 #include "kselftest.h"
16 #include "gcs-util.h"
17
18 /* nolibc doesn't have sysconf(), just hard code the maximum */
19 static size_t page_size = 65536;
20
valid_gcs_function(void)21 static __attribute__((noinline)) void valid_gcs_function(void)
22 {
23 /* Do something the compiler can't optimise out */
24 my_syscall1(__NR_prctl, PR_SVE_GET_VL);
25 }
26
gcs_set_status(unsigned long mode)27 static inline int gcs_set_status(unsigned long mode)
28 {
29 bool enabling = mode & PR_SHADOW_STACK_ENABLE;
30 int ret;
31 unsigned long new_mode;
32
33 /*
34 * The prctl takes 1 argument but we need to ensure that the
35 * other 3 values passed in registers to the syscall are zero
36 * since the kernel validates them.
37 */
38 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, mode,
39 0, 0, 0);
40
41 if (ret == 0) {
42 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
43 &new_mode, 0, 0, 0);
44 if (ret == 0) {
45 if (new_mode != mode) {
46 ksft_print_msg("Mode set to %lx not %lx\n",
47 new_mode, mode);
48 ret = -EINVAL;
49 }
50 } else {
51 ksft_print_msg("Failed to validate mode: %d\n", ret);
52 }
53
54 if (enabling != chkfeat_gcs()) {
55 ksft_print_msg("%senabled by prctl but %senabled in CHKFEAT\n",
56 enabling ? "" : "not ",
57 chkfeat_gcs() ? "" : "not ");
58 ret = -EINVAL;
59 }
60 }
61
62 return ret;
63 }
64
65 /* Try to read the status */
read_status(void)66 static bool read_status(void)
67 {
68 unsigned long state;
69 int ret;
70
71 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
72 &state, 0, 0, 0);
73 if (ret != 0) {
74 ksft_print_msg("Failed to read state: %d\n", ret);
75 return false;
76 }
77
78 return state & PR_SHADOW_STACK_ENABLE;
79 }
80
81 /* Just a straight enable */
base_enable(void)82 static bool base_enable(void)
83 {
84 int ret;
85
86 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
87 if (ret) {
88 ksft_print_msg("PR_SHADOW_STACK_ENABLE failed %d\n", ret);
89 return false;
90 }
91
92 return true;
93 }
94
95 /* Check we can read GCSPR_EL0 when GCS is enabled */
read_gcspr_el0(void)96 static bool read_gcspr_el0(void)
97 {
98 unsigned long *gcspr_el0;
99
100 ksft_print_msg("GET GCSPR\n");
101 gcspr_el0 = get_gcspr();
102 ksft_print_msg("GCSPR_EL0 is %p\n", gcspr_el0);
103
104 return true;
105 }
106
107 /* Also allow writes to stack */
enable_writeable(void)108 static bool enable_writeable(void)
109 {
110 int ret;
111
112 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE);
113 if (ret) {
114 ksft_print_msg("PR_SHADOW_STACK_ENABLE writeable failed: %d\n", ret);
115 return false;
116 }
117
118 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
119 if (ret) {
120 ksft_print_msg("failed to restore plain enable %d\n", ret);
121 return false;
122 }
123
124 return true;
125 }
126
127 /* Also allow writes to stack */
enable_push_pop(void)128 static bool enable_push_pop(void)
129 {
130 int ret;
131
132 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH);
133 if (ret) {
134 ksft_print_msg("PR_SHADOW_STACK_ENABLE with push failed: %d\n",
135 ret);
136 return false;
137 }
138
139 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
140 if (ret) {
141 ksft_print_msg("failed to restore plain enable %d\n", ret);
142 return false;
143 }
144
145 return true;
146 }
147
148 /* Enable GCS and allow everything */
enable_all(void)149 static bool enable_all(void)
150 {
151 int ret;
152
153 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH |
154 PR_SHADOW_STACK_WRITE);
155 if (ret) {
156 ksft_print_msg("PR_SHADOW_STACK_ENABLE with everything failed: %d\n",
157 ret);
158 return false;
159 }
160
161 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
162 if (ret) {
163 ksft_print_msg("failed to restore plain enable %d\n", ret);
164 return false;
165 }
166
167 return true;
168 }
169
enable_invalid(void)170 static bool enable_invalid(void)
171 {
172 int ret = gcs_set_status(ULONG_MAX);
173 if (ret == 0) {
174 ksft_print_msg("GCS_SET_STATUS %lx succeeded\n", ULONG_MAX);
175 return false;
176 }
177
178 return true;
179 }
180
181 /* Map a GCS */
map_guarded_stack(void)182 static bool map_guarded_stack(void)
183 {
184 int ret;
185 uint64_t *buf;
186 uint64_t expected_cap;
187 int elem;
188 bool pass = true;
189
190 buf = (void *)my_syscall3(__NR_map_shadow_stack, 0, page_size,
191 SHADOW_STACK_SET_MARKER |
192 SHADOW_STACK_SET_TOKEN);
193 if (buf == MAP_FAILED) {
194 ksft_print_msg("Failed to map %lu byte GCS: %d\n",
195 page_size, errno);
196 return false;
197 }
198 ksft_print_msg("Mapped GCS at %p-%p\n", buf,
199 (void *)((uint64_t)buf + page_size));
200
201 /* The top of the newly allocated region should be 0 */
202 elem = (page_size / sizeof(uint64_t)) - 1;
203 if (buf[elem]) {
204 ksft_print_msg("Last entry is 0x%llx not 0x0\n", buf[elem]);
205 pass = false;
206 }
207
208 /* Then a valid cap token */
209 elem--;
210 expected_cap = ((uint64_t)buf + page_size - 16);
211 expected_cap &= GCS_CAP_ADDR_MASK;
212 expected_cap |= GCS_CAP_VALID_TOKEN;
213 if (buf[elem] != expected_cap) {
214 ksft_print_msg("Cap entry is 0x%llx not 0x%llx\n",
215 buf[elem], expected_cap);
216 pass = false;
217 }
218 ksft_print_msg("cap token is 0x%llx\n", buf[elem]);
219
220 /* The rest should be zeros */
221 for (elem = 0; elem < page_size / sizeof(uint64_t) - 2; elem++) {
222 if (!buf[elem])
223 continue;
224 ksft_print_msg("GCS slot %d is 0x%llx not 0x0\n",
225 elem, buf[elem]);
226 pass = false;
227 }
228
229 ret = munmap(buf, page_size);
230 if (ret != 0) {
231 ksft_print_msg("Failed to unmap %ld byte GCS: %d\n",
232 page_size, errno);
233 pass = false;
234 }
235
236 return pass;
237 }
238
239 /* A fork()ed process can run */
test_fork(void)240 static bool test_fork(void)
241 {
242 unsigned long child_mode;
243 int ret, status;
244 pid_t pid;
245 bool pass = true;
246
247 pid = fork();
248 if (pid == -1) {
249 ksft_print_msg("fork() failed: %d\n", errno);
250 pass = false;
251 goto out;
252 }
253 if (pid == 0) {
254 /* In child, make sure we can call a function, read
255 * the GCS pointer and status and then exit */
256 valid_gcs_function();
257 get_gcspr();
258
259 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
260 &child_mode, 0, 0, 0);
261 if (ret == 0 && !(child_mode & PR_SHADOW_STACK_ENABLE)) {
262 ksft_print_msg("GCS not enabled in child\n");
263 ret = -EINVAL;
264 }
265
266 exit(ret);
267 }
268
269 /*
270 * In parent, check we can still do function calls then block
271 * for the child.
272 */
273 valid_gcs_function();
274
275 ksft_print_msg("Waiting for child %d\n", pid);
276
277 ret = waitpid(pid, &status, 0);
278 if (ret == -1) {
279 ksft_print_msg("Failed to wait for child: %d\n",
280 errno);
281 return false;
282 }
283
284 if (!WIFEXITED(status)) {
285 ksft_print_msg("Child exited due to signal %d\n",
286 WTERMSIG(status));
287 pass = false;
288 } else {
289 if (WEXITSTATUS(status)) {
290 ksft_print_msg("Child exited with status %d\n",
291 WEXITSTATUS(status));
292 pass = false;
293 }
294 }
295
296 out:
297
298 return pass;
299 }
300
301 /* A vfork()ed process can run and exit */
test_vfork(void)302 static bool test_vfork(void)
303 {
304 unsigned long child_mode;
305 int ret, status;
306 pid_t pid;
307 bool pass = true;
308
309 pid = vfork();
310 if (pid == -1) {
311 ksft_print_msg("vfork() failed: %d\n", errno);
312 pass = false;
313 goto out;
314 }
315 if (pid == 0) {
316 /*
317 * In child, make sure we can call a function, read
318 * the GCS pointer and status and then exit.
319 */
320 valid_gcs_function();
321 get_gcspr();
322
323 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
324 &child_mode, 0, 0, 0);
325 if (ret == 0 && !(child_mode & PR_SHADOW_STACK_ENABLE)) {
326 ksft_print_msg("GCS not enabled in child\n");
327 ret = EXIT_FAILURE;
328 }
329
330 _exit(ret);
331 }
332
333 /*
334 * In parent, check we can still do function calls then check
335 * on the child.
336 */
337 valid_gcs_function();
338
339 ksft_print_msg("Waiting for child %d\n", pid);
340
341 ret = waitpid(pid, &status, 0);
342 if (ret == -1) {
343 ksft_print_msg("Failed to wait for child: %d\n",
344 errno);
345 return false;
346 }
347
348 if (!WIFEXITED(status)) {
349 ksft_print_msg("Child exited due to signal %d\n",
350 WTERMSIG(status));
351 pass = false;
352 } else if (WEXITSTATUS(status)) {
353 ksft_print_msg("Child exited with status %d\n",
354 WEXITSTATUS(status));
355 pass = false;
356 }
357
358 out:
359
360 return pass;
361 }
362
363 typedef bool (*gcs_test)(void);
364
365 static struct {
366 char *name;
367 gcs_test test;
368 bool needs_enable;
369 } tests[] = {
370 { "read_status", read_status },
371 { "base_enable", base_enable, true },
372 { "read_gcspr_el0", read_gcspr_el0 },
373 { "enable_writeable", enable_writeable, true },
374 { "enable_push_pop", enable_push_pop, true },
375 { "enable_all", enable_all, true },
376 { "enable_invalid", enable_invalid, true },
377 { "map_guarded_stack", map_guarded_stack },
378 { "fork", test_fork },
379 { "vfork", test_vfork },
380 };
381
main(void)382 int main(void)
383 {
384 int i, ret;
385 unsigned long gcs_mode;
386
387 ksft_print_header();
388
389 /*
390 * We don't have getauxval() with nolibc so treat a failure to
391 * read GCS state as a lack of support and skip.
392 */
393 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
394 &gcs_mode, 0, 0, 0);
395 if (ret != 0)
396 ksft_exit_skip("Failed to read GCS state: %d\n", ret);
397
398 if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
399 gcs_mode = PR_SHADOW_STACK_ENABLE;
400 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
401 gcs_mode, 0, 0, 0);
402 if (ret != 0)
403 ksft_exit_fail_msg("Failed to enable GCS: %d\n", ret);
404 }
405
406 ksft_set_plan(ARRAY_SIZE(tests));
407
408 for (i = 0; i < ARRAY_SIZE(tests); i++) {
409 ksft_test_result((*tests[i].test)(), "%s\n", tests[i].name);
410 }
411
412 /* One last test: disable GCS, we can do this one time */
413 my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
414 if (ret != 0)
415 ksft_print_msg("Failed to disable GCS: %d\n", ret);
416
417 ksft_finished();
418
419 return 0;
420 }
421