xref: /linux/tools/testing/selftests/arm64/gcs/libc-gcs.c (revision 364eeb79a213fcf9164208b53764223ad522d6b3)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2023 ARM Limited.
4  */
5 
6 #define _GNU_SOURCE
7 
8 #include <pthread.h>
9 #include <stdbool.h>
10 
11 #include <sys/auxv.h>
12 #include <sys/mman.h>
13 #include <sys/prctl.h>
14 #include <sys/ptrace.h>
15 #include <sys/uio.h>
16 
17 #include <asm/hwcap.h>
18 #include <asm/mman.h>
19 
20 #include <linux/compiler.h>
21 
22 #include "kselftest_harness.h"
23 
24 #include "gcs-util.h"
25 
26 #define my_syscall2(num, arg1, arg2)                                          \
27 ({                                                                            \
28 	register long _num  __asm__ ("x8") = (num);                           \
29 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
30 	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
31 	register long _arg3 __asm__ ("x2") = 0;                               \
32 	register long _arg4 __asm__ ("x3") = 0;                               \
33 	register long _arg5 __asm__ ("x4") = 0;                               \
34 	                                                                      \
35 	__asm__  volatile (                                                   \
36 		"svc #0\n"                                                    \
37 		: "=r"(_arg1)                                                 \
38 		: "r"(_arg1), "r"(_arg2),                                     \
39 		  "r"(_arg3), "r"(_arg4),                                     \
40 		  "r"(_arg5), "r"(_num)					      \
41 		: "memory", "cc"                                              \
42 	);                                                                    \
43 	_arg1;                                                                \
44 })
45 
46 static noinline void gcs_recurse(int depth)
47 {
48 	if (depth)
49 		gcs_recurse(depth - 1);
50 
51 	/* Prevent tail call optimization so we actually recurse */
52 	asm volatile("dsb sy" : : : "memory");
53 }
54 
55 /* Smoke test that a function call and return works*/
56 TEST(can_call_function)
57 {
58 	gcs_recurse(0);
59 }
60 
61 static void *gcs_test_thread(void *arg)
62 {
63 	int ret;
64 	unsigned long mode;
65 
66 	/*
67 	 * Some libcs don't seem to fill unused arguments with 0 but
68 	 * the kernel validates this so we supply all 5 arguments.
69 	 */
70 	ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
71 	if (ret != 0) {
72 		ksft_print_msg("PR_GET_SHADOW_STACK_STATUS failed: %d\n", ret);
73 		return NULL;
74 	}
75 
76 	if (!(mode & PR_SHADOW_STACK_ENABLE)) {
77 		ksft_print_msg("GCS not enabled in thread, mode is %lu\n",
78 			       mode);
79 		return NULL;
80 	}
81 
82 	/* Just in case... */
83 	gcs_recurse(0);
84 
85 	/* Use a non-NULL value to indicate a pass */
86 	return &gcs_test_thread;
87 }
88 
89 /* Verify that if we start a new thread it has GCS enabled */
90 TEST(gcs_enabled_thread)
91 {
92 	pthread_t thread;
93 	void *thread_ret;
94 	int ret;
95 
96 	ret = pthread_create(&thread, NULL, gcs_test_thread, NULL);
97 	ASSERT_TRUE(ret == 0);
98 	if (ret != 0)
99 		return;
100 
101 	ret = pthread_join(thread, &thread_ret);
102 	ASSERT_TRUE(ret == 0);
103 	if (ret != 0)
104 		return;
105 
106 	ASSERT_TRUE(thread_ret != NULL);
107 }
108 
109 /* Read the GCS until we find the terminator */
110 TEST(gcs_find_terminator)
111 {
112 	unsigned long *gcs, *cur;
113 
114 	gcs = get_gcspr();
115 	cur = gcs;
116 	while (*cur)
117 		cur++;
118 
119 	ksft_print_msg("GCS in use from %p-%p\n", gcs, cur);
120 
121 	/*
122 	 * We should have at least whatever called into this test so
123 	 * the two pointer should differ.
124 	 */
125 	ASSERT_TRUE(gcs != cur);
126 }
127 
128 /*
129  * We can access a GCS via ptrace
130  *
131  * This could usefully have a fixture but note that each test is
132  * fork()ed into a new child whcih causes issues.  Might be better to
133  * lift at least some of this out into a separate, non-harness, test
134  * program.
135  */
136 TEST(ptrace_read_write)
137 {
138 	pid_t child, pid;
139 	int ret, status;
140 	siginfo_t si;
141 	uint64_t val, rval, gcspr;
142 	struct user_gcs child_gcs;
143 	struct iovec iov, local_iov, remote_iov;
144 
145 	child = fork();
146 	if (child == -1) {
147 		ksft_print_msg("fork() failed: %d (%s)\n",
148 			       errno, strerror(errno));
149 		ASSERT_NE(child, -1);
150 	}
151 
152 	if (child == 0) {
153 		/*
154 		 * In child, make sure there's something on the stack and
155 		 * ask to be traced.
156 		 */
157 		gcs_recurse(0);
158 		if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
159 			ksft_exit_fail_msg("PTRACE_TRACEME %s",
160 					   strerror(errno));
161 
162 		if (raise(SIGSTOP))
163 			ksft_exit_fail_msg("raise(SIGSTOP) %s",
164 					   strerror(errno));
165 
166 		return;
167 	}
168 
169 	ksft_print_msg("Child: %d\n", child);
170 
171 	/* Attach to the child */
172 	while (1) {
173 		int sig;
174 
175 		pid = wait(&status);
176 		if (pid == -1) {
177 			ksft_print_msg("wait() failed: %s",
178 				       strerror(errno));
179 			goto error;
180 		}
181 
182 		/*
183 		 * This should never happen but it's hard to flag in
184 		 * the framework.
185 		 */
186 		if (pid != child)
187 			continue;
188 
189 		if (WIFEXITED(status) || WIFSIGNALED(status))
190 			ksft_exit_fail_msg("Child died unexpectedly\n");
191 
192 		if (!WIFSTOPPED(status))
193 			goto error;
194 
195 		sig = WSTOPSIG(status);
196 
197 		if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
198 			if (errno == ESRCH) {
199 				ASSERT_NE(errno, ESRCH);
200 				return;
201 			}
202 
203 			if (errno == EINVAL) {
204 				sig = 0; /* bust group-stop */
205 				goto cont;
206 			}
207 
208 			ksft_print_msg("PTRACE_GETSIGINFO: %s\n",
209 				       strerror(errno));
210 			goto error;
211 		}
212 
213 		if (sig == SIGSTOP && si.si_code == SI_TKILL &&
214 		    si.si_pid == pid)
215 			break;
216 
217 	cont:
218 		if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
219 			if (errno == ESRCH) {
220 				ASSERT_NE(errno, ESRCH);
221 				return;
222 			}
223 
224 			ksft_print_msg("PTRACE_CONT: %s\n", strerror(errno));
225 			goto error;
226 		}
227 	}
228 
229 	/* Where is the child GCS? */
230 	iov.iov_base = &child_gcs;
231 	iov.iov_len = sizeof(child_gcs);
232 	ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_GCS, &iov);
233 	if (ret != 0) {
234 		ksft_print_msg("Failed to read child GCS state: %s (%d)\n",
235 			       strerror(errno), errno);
236 		goto error;
237 	}
238 
239 	/* We should have inherited GCS over fork(), confirm */
240 	if (!(child_gcs.features_enabled & PR_SHADOW_STACK_ENABLE)) {
241 		ASSERT_TRUE(child_gcs.features_enabled &
242 			    PR_SHADOW_STACK_ENABLE);
243 		goto error;
244 	}
245 
246 	gcspr = child_gcs.gcspr_el0;
247 	ksft_print_msg("Child GCSPR 0x%lx, flags %llx, locked %llx\n",
248 		       gcspr, child_gcs.features_enabled,
249 		       child_gcs.features_locked);
250 
251 	/* Ideally we'd cross check with the child memory map */
252 
253 	errno = 0;
254 	val = ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL);
255 	ret = errno;
256 	if (ret != 0)
257 		ksft_print_msg("PTRACE_PEEKDATA failed: %s (%d)\n",
258 			       strerror(ret), ret);
259 	EXPECT_EQ(ret, 0);
260 
261 	/* The child should be in a function, the GCSPR shouldn't be 0 */
262 	EXPECT_NE(val, 0);
263 
264 	/* Same thing via process_vm_readv() */
265 	local_iov.iov_base = &rval;
266 	local_iov.iov_len = sizeof(rval);
267 	remote_iov.iov_base = (void *)gcspr;
268 	remote_iov.iov_len = sizeof(rval);
269 	ret = process_vm_readv(child, &local_iov, 1, &remote_iov, 1, 0);
270 	if (ret == -1)
271 		ksft_print_msg("process_vm_readv() failed: %s (%d)\n",
272 			       strerror(errno), errno);
273 	EXPECT_EQ(ret, sizeof(rval));
274 	EXPECT_EQ(val, rval);
275 
276 	/* Write data via a peek */
277 	ret = ptrace(PTRACE_POKEDATA, child, (void *)gcspr, NULL);
278 	if (ret == -1)
279 		ksft_print_msg("PTRACE_POKEDATA failed: %s (%d)\n",
280 			       strerror(errno), errno);
281 	EXPECT_EQ(ret, 0);
282 	EXPECT_EQ(0, ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL));
283 
284 	/* Restore what we had before */
285 	ret = ptrace(PTRACE_POKEDATA, child, (void *)gcspr, val);
286 	if (ret == -1)
287 		ksft_print_msg("PTRACE_POKEDATA failed: %s (%d)\n",
288 			       strerror(errno), errno);
289 	EXPECT_EQ(ret, 0);
290 	EXPECT_EQ(val, ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL));
291 
292 	/* That's all, folks */
293 	kill(child, SIGKILL);
294 	return;
295 
296 error:
297 	kill(child, SIGKILL);
298 	ASSERT_FALSE(true);
299 }
300 
301 FIXTURE(map_gcs)
302 {
303 	unsigned long *stack;
304 };
305 
306 FIXTURE_VARIANT(map_gcs)
307 {
308 	size_t stack_size;
309 	unsigned long flags;
310 };
311 
312 FIXTURE_VARIANT_ADD(map_gcs, s2k_cap_marker)
313 {
314 	.stack_size = 2 * 1024,
315 	.flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
316 };
317 
318 FIXTURE_VARIANT_ADD(map_gcs, s2k_cap)
319 {
320 	.stack_size = 2 * 1024,
321 	.flags = SHADOW_STACK_SET_TOKEN,
322 };
323 
324 FIXTURE_VARIANT_ADD(map_gcs, s2k_marker)
325 {
326 	.stack_size = 2 * 1024,
327 	.flags = SHADOW_STACK_SET_MARKER,
328 };
329 
330 FIXTURE_VARIANT_ADD(map_gcs, s2k)
331 {
332 	.stack_size = 2 * 1024,
333 	.flags = 0,
334 };
335 
336 FIXTURE_VARIANT_ADD(map_gcs, s4k_cap_marker)
337 {
338 	.stack_size = 4 * 1024,
339 	.flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
340 };
341 
342 FIXTURE_VARIANT_ADD(map_gcs, s4k_cap)
343 {
344 	.stack_size = 4 * 1024,
345 	.flags = SHADOW_STACK_SET_TOKEN,
346 };
347 
348 FIXTURE_VARIANT_ADD(map_gcs, s3k_marker)
349 {
350 	.stack_size = 4 * 1024,
351 	.flags = SHADOW_STACK_SET_MARKER,
352 };
353 
354 FIXTURE_VARIANT_ADD(map_gcs, s4k)
355 {
356 	.stack_size = 4 * 1024,
357 	.flags = 0,
358 };
359 
360 FIXTURE_VARIANT_ADD(map_gcs, s16k_cap_marker)
361 {
362 	.stack_size = 16 * 1024,
363 	.flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
364 };
365 
366 FIXTURE_VARIANT_ADD(map_gcs, s16k_cap)
367 {
368 	.stack_size = 16 * 1024,
369 	.flags = SHADOW_STACK_SET_TOKEN,
370 };
371 
372 FIXTURE_VARIANT_ADD(map_gcs, s16k_marker)
373 {
374 	.stack_size = 16 * 1024,
375 	.flags = SHADOW_STACK_SET_MARKER,
376 };
377 
378 FIXTURE_VARIANT_ADD(map_gcs, s16k)
379 {
380 	.stack_size = 16 * 1024,
381 	.flags = 0,
382 };
383 
384 FIXTURE_VARIANT_ADD(map_gcs, s64k_cap_marker)
385 {
386 	.stack_size = 64 * 1024,
387 	.flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
388 };
389 
390 FIXTURE_VARIANT_ADD(map_gcs, s64k_cap)
391 {
392 	.stack_size = 64 * 1024,
393 	.flags = SHADOW_STACK_SET_TOKEN,
394 };
395 
396 FIXTURE_VARIANT_ADD(map_gcs, s64k_marker)
397 {
398 	.stack_size = 64 * 1024,
399 	.flags = SHADOW_STACK_SET_MARKER,
400 };
401 
402 FIXTURE_VARIANT_ADD(map_gcs, s64k)
403 {
404 	.stack_size = 64 * 1024,
405 	.flags = 0,
406 };
407 
408 FIXTURE_VARIANT_ADD(map_gcs, s128k_cap_marker)
409 {
410 	.stack_size = 128 * 1024,
411 	.flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
412 };
413 
414 FIXTURE_VARIANT_ADD(map_gcs, s128k_cap)
415 {
416 	.stack_size = 128 * 1024,
417 	.flags = SHADOW_STACK_SET_TOKEN,
418 };
419 
420 FIXTURE_VARIANT_ADD(map_gcs, s128k_marker)
421 {
422 	.stack_size = 128 * 1024,
423 	.flags = SHADOW_STACK_SET_MARKER,
424 };
425 
426 FIXTURE_VARIANT_ADD(map_gcs, s128k)
427 {
428 	.stack_size = 128 * 1024,
429 	.flags = 0,
430 };
431 
432 FIXTURE_SETUP(map_gcs)
433 {
434 	self->stack = (void *)syscall(__NR_map_shadow_stack, 0,
435 				      variant->stack_size,
436 				      variant->flags);
437 	ASSERT_FALSE(self->stack == MAP_FAILED);
438 	ksft_print_msg("Allocated stack from %p-%p\n", self->stack,
439 		       self->stack + variant->stack_size);
440 }
441 
442 FIXTURE_TEARDOWN(map_gcs)
443 {
444 	int ret;
445 
446 	if (self->stack != MAP_FAILED) {
447 		ret = munmap(self->stack, variant->stack_size);
448 		ASSERT_EQ(ret, 0);
449 	}
450 }
451 
452 /* The stack has a cap token */
453 TEST_F(map_gcs, stack_capped)
454 {
455 	unsigned long *stack = self->stack;
456 	size_t cap_index;
457 
458 	cap_index = (variant->stack_size / sizeof(unsigned long));
459 
460 	switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) {
461 	case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN:
462 		cap_index -= 2;
463 		break;
464 	case SHADOW_STACK_SET_TOKEN:
465 		cap_index -= 1;
466 		break;
467 	case SHADOW_STACK_SET_MARKER:
468 	case 0:
469 		/* No cap, no test */
470 		return;
471 	}
472 
473 	ASSERT_EQ(stack[cap_index], GCS_CAP(&stack[cap_index]));
474 }
475 
476 /* The top of the stack is 0 */
477 TEST_F(map_gcs, stack_terminated)
478 {
479 	unsigned long *stack = self->stack;
480 	size_t term_index;
481 
482 	if (!(variant->flags & SHADOW_STACK_SET_MARKER))
483 		return;
484 
485 	term_index = (variant->stack_size / sizeof(unsigned long)) - 1;
486 
487 	ASSERT_EQ(stack[term_index], 0);
488 }
489 
490 /* Writes should fault */
491 TEST_F_SIGNAL(map_gcs, not_writeable, SIGSEGV)
492 {
493 	self->stack[0] = 0;
494 }
495 
496 /* Put it all together, we can safely switch to and from the stack */
497 TEST_F(map_gcs, stack_switch)
498 {
499 	size_t cap_index;
500 	cap_index = (variant->stack_size / sizeof(unsigned long));
501 	unsigned long *orig_gcspr_el0, *pivot_gcspr_el0;
502 
503 	/* Skip over the stack terminator and point at the cap */
504 	switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) {
505 	case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN:
506 		cap_index -= 2;
507 		break;
508 	case SHADOW_STACK_SET_TOKEN:
509 		cap_index -= 1;
510 		break;
511 	case SHADOW_STACK_SET_MARKER:
512 	case 0:
513 		/* No cap, no test */
514 		return;
515 	}
516 	pivot_gcspr_el0 = &self->stack[cap_index];
517 
518 	/* Pivot to the new GCS */
519 	ksft_print_msg("Pivoting to %p from %p, target has value 0x%lx\n",
520 		       pivot_gcspr_el0, get_gcspr(),
521 		       *pivot_gcspr_el0);
522 	gcsss1(pivot_gcspr_el0);
523 	orig_gcspr_el0 = gcsss2();
524 	ksft_print_msg("Pivoted to %p from %p, target has value 0x%lx\n",
525 		       get_gcspr(), orig_gcspr_el0,
526 		       *pivot_gcspr_el0);
527 
528 	ksft_print_msg("Pivoted, GCSPR_EL0 now %p\n", get_gcspr());
529 
530 	/* New GCS must be in the new buffer */
531 	ASSERT_TRUE((unsigned long)get_gcspr() > (unsigned long)self->stack);
532 	ASSERT_TRUE((unsigned long)get_gcspr() <=
533 		    (unsigned long)self->stack + variant->stack_size);
534 
535 	/* We should be able to use all but 2 slots of the new stack */
536 	ksft_print_msg("Recursing %zu levels\n", cap_index - 1);
537 	gcs_recurse(cap_index - 1);
538 
539 	/* Pivot back to the original GCS */
540 	gcsss1(orig_gcspr_el0);
541 	pivot_gcspr_el0 = gcsss2();
542 
543 	gcs_recurse(0);
544 	ksft_print_msg("Pivoted back to GCSPR_EL0 0x%p\n", get_gcspr());
545 }
546 
547 /* We fault if we try to go beyond the end of the stack */
548 TEST_F_SIGNAL(map_gcs, stack_overflow, SIGSEGV)
549 {
550 	size_t cap_index;
551 	cap_index = (variant->stack_size / sizeof(unsigned long));
552 	unsigned long *orig_gcspr_el0, *pivot_gcspr_el0;
553 
554 	/* Skip over the stack terminator and point at the cap */
555 	switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) {
556 	case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN:
557 		cap_index -= 2;
558 		break;
559 	case SHADOW_STACK_SET_TOKEN:
560 		cap_index -= 1;
561 		break;
562 	case SHADOW_STACK_SET_MARKER:
563 	case 0:
564 		/* No cap, no test but we need to SEGV to avoid a false fail */
565 		orig_gcspr_el0 = get_gcspr();
566 		*orig_gcspr_el0 = 0;
567 		return;
568 	}
569 	pivot_gcspr_el0 = &self->stack[cap_index];
570 
571 	/* Pivot to the new GCS */
572 	ksft_print_msg("Pivoting to %p from %p, target has value 0x%lx\n",
573 		       pivot_gcspr_el0, get_gcspr(),
574 		       *pivot_gcspr_el0);
575 	gcsss1(pivot_gcspr_el0);
576 	orig_gcspr_el0 = gcsss2();
577 	ksft_print_msg("Pivoted to %p from %p, target has value 0x%lx\n",
578 		       pivot_gcspr_el0, orig_gcspr_el0,
579 		       *pivot_gcspr_el0);
580 
581 	ksft_print_msg("Pivoted, GCSPR_EL0 now %p\n", get_gcspr());
582 
583 	/* New GCS must be in the new buffer */
584 	ASSERT_TRUE((unsigned long)get_gcspr() > (unsigned long)self->stack);
585 	ASSERT_TRUE((unsigned long)get_gcspr() <=
586 		    (unsigned long)self->stack + variant->stack_size);
587 
588 	/* Now try to recurse, we should fault doing this. */
589 	ksft_print_msg("Recursing %zu levels...\n", cap_index + 1);
590 	gcs_recurse(cap_index + 1);
591 	ksft_print_msg("...done\n");
592 
593 	/* Clean up properly to try to guard against spurious passes. */
594 	gcsss1(orig_gcspr_el0);
595 	pivot_gcspr_el0 = gcsss2();
596 	ksft_print_msg("Pivoted back to GCSPR_EL0 0x%p\n", get_gcspr());
597 }
598 
599 FIXTURE(map_invalid_gcs)
600 {
601 };
602 
603 FIXTURE_VARIANT(map_invalid_gcs)
604 {
605 	size_t stack_size;
606 };
607 
608 FIXTURE_SETUP(map_invalid_gcs)
609 {
610 }
611 
612 FIXTURE_TEARDOWN(map_invalid_gcs)
613 {
614 }
615 
616 /* GCS must be larger than 16 bytes */
617 FIXTURE_VARIANT_ADD(map_invalid_gcs, too_small)
618 {
619 	.stack_size = 8,
620 };
621 
622 /* GCS size must be 16 byte aligned */
623 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_1)  { .stack_size = 1024 + 1  };
624 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_2)  { .stack_size = 1024 + 2  };
625 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_3)  { .stack_size = 1024 + 3  };
626 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_4)  { .stack_size = 1024 + 4  };
627 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_5)  { .stack_size = 1024 + 5  };
628 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_6)  { .stack_size = 1024 + 6  };
629 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_7)  { .stack_size = 1024 + 7  };
630 
631 TEST_F(map_invalid_gcs, do_map)
632 {
633 	void *stack;
634 
635 	stack = (void *)syscall(__NR_map_shadow_stack, 0,
636 				variant->stack_size, 0);
637 	ASSERT_TRUE(stack == MAP_FAILED);
638 	if (stack != MAP_FAILED)
639 		munmap(stack, variant->stack_size);
640 }
641 
642 FIXTURE(invalid_mprotect)
643 {
644 	unsigned long *stack;
645 	size_t stack_size;
646 };
647 
648 FIXTURE_VARIANT(invalid_mprotect)
649 {
650 	unsigned long flags;
651 };
652 
653 FIXTURE_SETUP(invalid_mprotect)
654 {
655 	self->stack_size = sysconf(_SC_PAGE_SIZE);
656 	self->stack = (void *)syscall(__NR_map_shadow_stack, 0,
657 				      self->stack_size, 0);
658 	ASSERT_FALSE(self->stack == MAP_FAILED);
659 	ksft_print_msg("Allocated stack from %p-%p\n", self->stack,
660 		       self->stack + self->stack_size);
661 }
662 
663 FIXTURE_TEARDOWN(invalid_mprotect)
664 {
665 	int ret;
666 
667 	if (self->stack != MAP_FAILED) {
668 		ret = munmap(self->stack, self->stack_size);
669 		ASSERT_EQ(ret, 0);
670 	}
671 }
672 
673 FIXTURE_VARIANT_ADD(invalid_mprotect, exec)
674 {
675 	.flags = PROT_EXEC,
676 };
677 
678 TEST_F(invalid_mprotect, do_map)
679 {
680 	int ret;
681 
682 	ret = mprotect(self->stack, self->stack_size, variant->flags);
683 	ASSERT_EQ(ret, -1);
684 }
685 
686 TEST_F(invalid_mprotect, do_map_read)
687 {
688 	int ret;
689 
690 	ret = mprotect(self->stack, self->stack_size,
691 		       variant->flags | PROT_READ);
692 	ASSERT_EQ(ret, -1);
693 }
694 
695 int main(int argc, char **argv)
696 {
697 	unsigned long gcs_mode;
698 	int ret;
699 
700 	if (!(getauxval(AT_HWCAP) & HWCAP_GCS))
701 		ksft_exit_skip("SKIP GCS not supported\n");
702 
703 	/*
704 	 * Force shadow stacks on, our tests *should* be fine with or
705 	 * without libc support and with or without this having ended
706 	 * up tagged for GCS and enabled by the dynamic linker.  We
707 	 * can't use the libc prctl() function since we can't return
708 	 * from enabling the stack.
709 	 */
710 	ret = my_syscall2(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
711 	if (ret) {
712 		ksft_print_msg("Failed to read GCS state: %d\n", ret);
713 		return EXIT_FAILURE;
714 	}
715 
716 	if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
717 		gcs_mode = PR_SHADOW_STACK_ENABLE;
718 		ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
719 				  gcs_mode);
720 		if (ret) {
721 			ksft_print_msg("Failed to configure GCS: %d\n", ret);
722 			return EXIT_FAILURE;
723 		}
724 	}
725 
726 	/* Avoid returning in case libc doesn't understand GCS */
727 	exit(test_harness_run(argc, argv));
728 }
729