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