xref: /linux/tools/testing/selftests/arm64/gcs/basic-gcs.c (revision 663a917475530feff868a4f2bda286ea4171f420)
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 
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 
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 */
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 */
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 */
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 */
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 */
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 */
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 
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 */
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 */
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 typedef bool (*gcs_test)(void);
302 
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 },
317 };
318 
319 int main(void)
320 {
321 	int i, ret;
322 	unsigned long gcs_mode;
323 
324 	ksft_print_header();
325 
326 	/*
327 	 * We don't have getauxval() with nolibc so treat a failure to
328 	 * read GCS state as a lack of support and skip.
329 	 */
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);
334 
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);
341 	}
342 
343 	ksft_set_plan(ARRAY_SIZE(tests));
344 
345 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
346 		ksft_test_result((*tests[i].test)(), "%s\n", tests[i].name);
347 	}
348 
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);
353 
354 	ksft_finished();
355 
356 	return 0;
357 }
358