Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / arm64 / gcs / basic-gcs.c
blob3fb9742342a349f732712fb92270134b586f3c3e
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2023 ARM Limited.
4 */
6 #include <limits.h>
7 #include <stdbool.h>
9 #include <linux/prctl.h>
11 #include <sys/mman.h>
12 #include <asm/mman.h>
13 #include <linux/sched.h>
15 #include "kselftest.h"
16 #include "gcs-util.h"
18 /* nolibc doesn't have sysconf(), just hard code the maximum */
19 static size_t page_size = 65536;
21 static __attribute__((noinline)) void valid_gcs_function(void)
23 /* Do something the compiler can't optimise out */
24 my_syscall1(__NR_prctl, PR_SVE_GET_VL);
27 static inline int gcs_set_status(unsigned long mode)
29 bool enabling = mode & PR_SHADOW_STACK_ENABLE;
30 int ret;
31 unsigned long new_mode;
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.
38 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, mode,
39 0, 0, 0);
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;
50 } else {
51 ksft_print_msg("Failed to validate mode: %d\n", ret);
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;
62 return ret;
65 /* Try to read the status */
66 static bool read_status(void)
68 unsigned long state;
69 int ret;
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;
78 return state & PR_SHADOW_STACK_ENABLE;
81 /* Just a straight enable */
82 static bool base_enable(void)
84 int ret;
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;
92 return true;
95 /* Check we can read GCSPR_EL0 when GCS is enabled */
96 static bool read_gcspr_el0(void)
98 unsigned long *gcspr_el0;
100 ksft_print_msg("GET GCSPR\n");
101 gcspr_el0 = get_gcspr();
102 ksft_print_msg("GCSPR_EL0 is %p\n", gcspr_el0);
104 return true;
107 /* Also allow writes to stack */
108 static bool enable_writeable(void)
110 int ret;
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;
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;
124 return true;
127 /* Also allow writes to stack */
128 static bool enable_push_pop(void)
130 int ret;
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;
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;
145 return true;
148 /* Enable GCS and allow everything */
149 static bool enable_all(void)
151 int ret;
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;
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;
167 return true;
170 static bool enable_invalid(void)
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;
178 return true;
181 /* Map a GCS */
182 static bool map_guarded_stack(void)
184 int ret;
185 uint64_t *buf;
186 uint64_t expected_cap;
187 int elem;
188 bool pass = true;
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;
198 ksft_print_msg("Mapped GCS at %p-%p\n", buf,
199 (void *)((uint64_t)buf + page_size));
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;
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;
218 ksft_print_msg("cap token is 0x%llx\n", buf[elem]);
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;
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;
236 return pass;
239 /* A fork()ed process can run */
240 static bool test_fork(void)
242 unsigned long child_mode;
243 int ret, status;
244 pid_t pid;
245 bool pass = true;
247 pid = fork();
248 if (pid == -1) {
249 ksft_print_msg("fork() failed: %d\n", errno);
250 pass = false;
251 goto out;
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();
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;
266 exit(ret);
270 * In parent, check we can still do function calls then block
271 * for the child.
273 valid_gcs_function();
275 ksft_print_msg("Waiting for child %d\n", pid);
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;
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;
296 out:
298 return pass;
301 typedef bool (*gcs_test)(void);
303 static struct {
304 char *name;
305 gcs_test test;
306 bool needs_enable;
307 } tests[] = {
308 { "read_status", read_status },
309 { "base_enable", base_enable, true },
310 { "read_gcspr_el0", read_gcspr_el0 },
311 { "enable_writeable", enable_writeable, true },
312 { "enable_push_pop", enable_push_pop, true },
313 { "enable_all", enable_all, true },
314 { "enable_invalid", enable_invalid, true },
315 { "map_guarded_stack", map_guarded_stack },
316 { "fork", test_fork },
319 int main(void)
321 int i, ret;
322 unsigned long gcs_mode;
324 ksft_print_header();
327 * We don't have getauxval() with nolibc so treat a failure to
328 * read GCS state as a lack of support and skip.
330 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
331 &gcs_mode, 0, 0, 0);
332 if (ret != 0)
333 ksft_exit_skip("Failed to read GCS state: %d\n", ret);
335 if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
336 gcs_mode = PR_SHADOW_STACK_ENABLE;
337 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
338 gcs_mode, 0, 0, 0);
339 if (ret != 0)
340 ksft_exit_fail_msg("Failed to enable GCS: %d\n", ret);
343 ksft_set_plan(ARRAY_SIZE(tests));
345 for (i = 0; i < ARRAY_SIZE(tests); i++) {
346 ksft_test_result((*tests[i].test)(), "%s\n", tests[i].name);
349 /* One last test: disable GCS, we can do this one time */
350 my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
351 if (ret != 0)
352 ksft_print_msg("Failed to disable GCS: %d\n", ret);
354 ksft_finished();
356 return 0;