xref: /linux/tools/testing/selftests/x86/test_shadow_stack.c (revision 81f30337ef4f9802f732e712be8d77dd6a32abbe)
1*81f30337SRick Edgecombe // SPDX-License-Identifier: GPL-2.0
2*81f30337SRick Edgecombe /*
3*81f30337SRick Edgecombe  * This program test's basic kernel shadow stack support. It enables shadow
4*81f30337SRick Edgecombe  * stack manual via the arch_prctl(), instead of relying on glibc. It's
5*81f30337SRick Edgecombe  * Makefile doesn't compile with shadow stack support, so it doesn't rely on
6*81f30337SRick Edgecombe  * any particular glibc. As a result it can't do any operations that require
7*81f30337SRick Edgecombe  * special glibc shadow stack support (longjmp(), swapcontext(), etc). Just
8*81f30337SRick Edgecombe  * stick to the basics and hope the compiler doesn't do anything strange.
9*81f30337SRick Edgecombe  */
10*81f30337SRick Edgecombe 
11*81f30337SRick Edgecombe #define _GNU_SOURCE
12*81f30337SRick Edgecombe 
13*81f30337SRick Edgecombe #include <sys/syscall.h>
14*81f30337SRick Edgecombe #include <asm/mman.h>
15*81f30337SRick Edgecombe #include <sys/mman.h>
16*81f30337SRick Edgecombe #include <sys/stat.h>
17*81f30337SRick Edgecombe #include <sys/wait.h>
18*81f30337SRick Edgecombe #include <stdio.h>
19*81f30337SRick Edgecombe #include <stdlib.h>
20*81f30337SRick Edgecombe #include <fcntl.h>
21*81f30337SRick Edgecombe #include <unistd.h>
22*81f30337SRick Edgecombe #include <string.h>
23*81f30337SRick Edgecombe #include <errno.h>
24*81f30337SRick Edgecombe #include <stdbool.h>
25*81f30337SRick Edgecombe #include <x86intrin.h>
26*81f30337SRick Edgecombe #include <asm/prctl.h>
27*81f30337SRick Edgecombe #include <sys/prctl.h>
28*81f30337SRick Edgecombe #include <stdint.h>
29*81f30337SRick Edgecombe #include <signal.h>
30*81f30337SRick Edgecombe #include <pthread.h>
31*81f30337SRick Edgecombe #include <sys/ioctl.h>
32*81f30337SRick Edgecombe #include <linux/userfaultfd.h>
33*81f30337SRick Edgecombe #include <setjmp.h>
34*81f30337SRick Edgecombe #include <sys/ptrace.h>
35*81f30337SRick Edgecombe #include <sys/signal.h>
36*81f30337SRick Edgecombe #include <linux/elf.h>
37*81f30337SRick Edgecombe 
38*81f30337SRick Edgecombe /*
39*81f30337SRick Edgecombe  * Define the ABI defines if needed, so people can run the tests
40*81f30337SRick Edgecombe  * without building the headers.
41*81f30337SRick Edgecombe  */
42*81f30337SRick Edgecombe #ifndef __NR_map_shadow_stack
43*81f30337SRick Edgecombe #define __NR_map_shadow_stack	452
44*81f30337SRick Edgecombe 
45*81f30337SRick Edgecombe #define SHADOW_STACK_SET_TOKEN	(1ULL << 0)
46*81f30337SRick Edgecombe 
47*81f30337SRick Edgecombe #define ARCH_SHSTK_ENABLE	0x5001
48*81f30337SRick Edgecombe #define ARCH_SHSTK_DISABLE	0x5002
49*81f30337SRick Edgecombe #define ARCH_SHSTK_LOCK		0x5003
50*81f30337SRick Edgecombe #define ARCH_SHSTK_UNLOCK	0x5004
51*81f30337SRick Edgecombe #define ARCH_SHSTK_STATUS	0x5005
52*81f30337SRick Edgecombe 
53*81f30337SRick Edgecombe #define ARCH_SHSTK_SHSTK	(1ULL <<  0)
54*81f30337SRick Edgecombe #define ARCH_SHSTK_WRSS		(1ULL <<  1)
55*81f30337SRick Edgecombe 
56*81f30337SRick Edgecombe #define NT_X86_SHSTK	0x204
57*81f30337SRick Edgecombe #endif
58*81f30337SRick Edgecombe 
59*81f30337SRick Edgecombe #define SS_SIZE 0x200000
60*81f30337SRick Edgecombe #define PAGE_SIZE 0x1000
61*81f30337SRick Edgecombe 
62*81f30337SRick Edgecombe #if (__GNUC__ < 8) || (__GNUC__ == 8 && __GNUC_MINOR__ < 5)
63*81f30337SRick Edgecombe int main(int argc, char *argv[])
64*81f30337SRick Edgecombe {
65*81f30337SRick Edgecombe 	printf("[SKIP]\tCompiler does not support CET.\n");
66*81f30337SRick Edgecombe 	return 0;
67*81f30337SRick Edgecombe }
68*81f30337SRick Edgecombe #else
69*81f30337SRick Edgecombe void write_shstk(unsigned long *addr, unsigned long val)
70*81f30337SRick Edgecombe {
71*81f30337SRick Edgecombe 	asm volatile("wrssq %[val], (%[addr])\n"
72*81f30337SRick Edgecombe 		     : "=m" (addr)
73*81f30337SRick Edgecombe 		     : [addr] "r" (addr), [val] "r" (val));
74*81f30337SRick Edgecombe }
75*81f30337SRick Edgecombe 
76*81f30337SRick Edgecombe static inline unsigned long __attribute__((always_inline)) get_ssp(void)
77*81f30337SRick Edgecombe {
78*81f30337SRick Edgecombe 	unsigned long ret = 0;
79*81f30337SRick Edgecombe 
80*81f30337SRick Edgecombe 	asm volatile("xor %0, %0; rdsspq %0" : "=r" (ret));
81*81f30337SRick Edgecombe 	return ret;
82*81f30337SRick Edgecombe }
83*81f30337SRick Edgecombe 
84*81f30337SRick Edgecombe /*
85*81f30337SRick Edgecombe  * For use in inline enablement of shadow stack.
86*81f30337SRick Edgecombe  *
87*81f30337SRick Edgecombe  * The program can't return from the point where shadow stack gets enabled
88*81f30337SRick Edgecombe  * because there will be no address on the shadow stack. So it can't use
89*81f30337SRick Edgecombe  * syscall() for enablement, since it is a function.
90*81f30337SRick Edgecombe  *
91*81f30337SRick Edgecombe  * Based on code from nolibc.h. Keep a copy here because this can't pull in all
92*81f30337SRick Edgecombe  * of nolibc.h.
93*81f30337SRick Edgecombe  */
94*81f30337SRick Edgecombe #define ARCH_PRCTL(arg1, arg2)					\
95*81f30337SRick Edgecombe ({								\
96*81f30337SRick Edgecombe 	long _ret;						\
97*81f30337SRick Edgecombe 	register long _num  asm("eax") = __NR_arch_prctl;	\
98*81f30337SRick Edgecombe 	register long _arg1 asm("rdi") = (long)(arg1);		\
99*81f30337SRick Edgecombe 	register long _arg2 asm("rsi") = (long)(arg2);		\
100*81f30337SRick Edgecombe 								\
101*81f30337SRick Edgecombe 	asm volatile (						\
102*81f30337SRick Edgecombe 		"syscall\n"					\
103*81f30337SRick Edgecombe 		: "=a"(_ret)					\
104*81f30337SRick Edgecombe 		: "r"(_arg1), "r"(_arg2),			\
105*81f30337SRick Edgecombe 		  "0"(_num)					\
106*81f30337SRick Edgecombe 		: "rcx", "r11", "memory", "cc"			\
107*81f30337SRick Edgecombe 	);							\
108*81f30337SRick Edgecombe 	_ret;							\
109*81f30337SRick Edgecombe })
110*81f30337SRick Edgecombe 
111*81f30337SRick Edgecombe void *create_shstk(void *addr)
112*81f30337SRick Edgecombe {
113*81f30337SRick Edgecombe 	return (void *)syscall(__NR_map_shadow_stack, addr, SS_SIZE, SHADOW_STACK_SET_TOKEN);
114*81f30337SRick Edgecombe }
115*81f30337SRick Edgecombe 
116*81f30337SRick Edgecombe void *create_normal_mem(void *addr)
117*81f30337SRick Edgecombe {
118*81f30337SRick Edgecombe 	return mmap(addr, SS_SIZE, PROT_READ | PROT_WRITE,
119*81f30337SRick Edgecombe 		    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
120*81f30337SRick Edgecombe }
121*81f30337SRick Edgecombe 
122*81f30337SRick Edgecombe void free_shstk(void *shstk)
123*81f30337SRick Edgecombe {
124*81f30337SRick Edgecombe 	munmap(shstk, SS_SIZE);
125*81f30337SRick Edgecombe }
126*81f30337SRick Edgecombe 
127*81f30337SRick Edgecombe int reset_shstk(void *shstk)
128*81f30337SRick Edgecombe {
129*81f30337SRick Edgecombe 	return madvise(shstk, SS_SIZE, MADV_DONTNEED);
130*81f30337SRick Edgecombe }
131*81f30337SRick Edgecombe 
132*81f30337SRick Edgecombe void try_shstk(unsigned long new_ssp)
133*81f30337SRick Edgecombe {
134*81f30337SRick Edgecombe 	unsigned long ssp;
135*81f30337SRick Edgecombe 
136*81f30337SRick Edgecombe 	printf("[INFO]\tnew_ssp = %lx, *new_ssp = %lx\n",
137*81f30337SRick Edgecombe 	       new_ssp, *((unsigned long *)new_ssp));
138*81f30337SRick Edgecombe 
139*81f30337SRick Edgecombe 	ssp = get_ssp();
140*81f30337SRick Edgecombe 	printf("[INFO]\tchanging ssp from %lx to %lx\n", ssp, new_ssp);
141*81f30337SRick Edgecombe 
142*81f30337SRick Edgecombe 	asm volatile("rstorssp (%0)\n":: "r" (new_ssp));
143*81f30337SRick Edgecombe 	asm volatile("saveprevssp");
144*81f30337SRick Edgecombe 	printf("[INFO]\tssp is now %lx\n", get_ssp());
145*81f30337SRick Edgecombe 
146*81f30337SRick Edgecombe 	/* Switch back to original shadow stack */
147*81f30337SRick Edgecombe 	ssp -= 8;
148*81f30337SRick Edgecombe 	asm volatile("rstorssp (%0)\n":: "r" (ssp));
149*81f30337SRick Edgecombe 	asm volatile("saveprevssp");
150*81f30337SRick Edgecombe }
151*81f30337SRick Edgecombe 
152*81f30337SRick Edgecombe int test_shstk_pivot(void)
153*81f30337SRick Edgecombe {
154*81f30337SRick Edgecombe 	void *shstk = create_shstk(0);
155*81f30337SRick Edgecombe 
156*81f30337SRick Edgecombe 	if (shstk == MAP_FAILED) {
157*81f30337SRick Edgecombe 		printf("[FAIL]\tError creating shadow stack: %d\n", errno);
158*81f30337SRick Edgecombe 		return 1;
159*81f30337SRick Edgecombe 	}
160*81f30337SRick Edgecombe 	try_shstk((unsigned long)shstk + SS_SIZE - 8);
161*81f30337SRick Edgecombe 	free_shstk(shstk);
162*81f30337SRick Edgecombe 
163*81f30337SRick Edgecombe 	printf("[OK]\tShadow stack pivot\n");
164*81f30337SRick Edgecombe 	return 0;
165*81f30337SRick Edgecombe }
166*81f30337SRick Edgecombe 
167*81f30337SRick Edgecombe int test_shstk_faults(void)
168*81f30337SRick Edgecombe {
169*81f30337SRick Edgecombe 	unsigned long *shstk = create_shstk(0);
170*81f30337SRick Edgecombe 
171*81f30337SRick Edgecombe 	/* Read shadow stack, test if it's zero to not get read optimized out */
172*81f30337SRick Edgecombe 	if (*shstk != 0)
173*81f30337SRick Edgecombe 		goto err;
174*81f30337SRick Edgecombe 
175*81f30337SRick Edgecombe 	/* Wrss memory that was already read. */
176*81f30337SRick Edgecombe 	write_shstk(shstk, 1);
177*81f30337SRick Edgecombe 	if (*shstk != 1)
178*81f30337SRick Edgecombe 		goto err;
179*81f30337SRick Edgecombe 
180*81f30337SRick Edgecombe 	/* Page out memory, so we can wrss it again. */
181*81f30337SRick Edgecombe 	if (reset_shstk((void *)shstk))
182*81f30337SRick Edgecombe 		goto err;
183*81f30337SRick Edgecombe 
184*81f30337SRick Edgecombe 	write_shstk(shstk, 1);
185*81f30337SRick Edgecombe 	if (*shstk != 1)
186*81f30337SRick Edgecombe 		goto err;
187*81f30337SRick Edgecombe 
188*81f30337SRick Edgecombe 	printf("[OK]\tShadow stack faults\n");
189*81f30337SRick Edgecombe 	return 0;
190*81f30337SRick Edgecombe 
191*81f30337SRick Edgecombe err:
192*81f30337SRick Edgecombe 	return 1;
193*81f30337SRick Edgecombe }
194*81f30337SRick Edgecombe 
195*81f30337SRick Edgecombe unsigned long saved_ssp;
196*81f30337SRick Edgecombe unsigned long saved_ssp_val;
197*81f30337SRick Edgecombe volatile bool segv_triggered;
198*81f30337SRick Edgecombe 
199*81f30337SRick Edgecombe void __attribute__((noinline)) violate_ss(void)
200*81f30337SRick Edgecombe {
201*81f30337SRick Edgecombe 	saved_ssp = get_ssp();
202*81f30337SRick Edgecombe 	saved_ssp_val = *(unsigned long *)saved_ssp;
203*81f30337SRick Edgecombe 
204*81f30337SRick Edgecombe 	/* Corrupt shadow stack */
205*81f30337SRick Edgecombe 	printf("[INFO]\tCorrupting shadow stack\n");
206*81f30337SRick Edgecombe 	write_shstk((void *)saved_ssp, 0);
207*81f30337SRick Edgecombe }
208*81f30337SRick Edgecombe 
209*81f30337SRick Edgecombe void segv_handler(int signum, siginfo_t *si, void *uc)
210*81f30337SRick Edgecombe {
211*81f30337SRick Edgecombe 	printf("[INFO]\tGenerated shadow stack violation successfully\n");
212*81f30337SRick Edgecombe 
213*81f30337SRick Edgecombe 	segv_triggered = true;
214*81f30337SRick Edgecombe 
215*81f30337SRick Edgecombe 	/* Fix shadow stack */
216*81f30337SRick Edgecombe 	write_shstk((void *)saved_ssp, saved_ssp_val);
217*81f30337SRick Edgecombe }
218*81f30337SRick Edgecombe 
219*81f30337SRick Edgecombe int test_shstk_violation(void)
220*81f30337SRick Edgecombe {
221*81f30337SRick Edgecombe 	struct sigaction sa = {};
222*81f30337SRick Edgecombe 
223*81f30337SRick Edgecombe 	sa.sa_sigaction = segv_handler;
224*81f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
225*81f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
226*81f30337SRick Edgecombe 		return 1;
227*81f30337SRick Edgecombe 
228*81f30337SRick Edgecombe 	segv_triggered = false;
229*81f30337SRick Edgecombe 
230*81f30337SRick Edgecombe 	/* Make sure segv_triggered is set before violate_ss() */
231*81f30337SRick Edgecombe 	asm volatile("" : : : "memory");
232*81f30337SRick Edgecombe 
233*81f30337SRick Edgecombe 	violate_ss();
234*81f30337SRick Edgecombe 
235*81f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
236*81f30337SRick Edgecombe 
237*81f30337SRick Edgecombe 	printf("[OK]\tShadow stack violation test\n");
238*81f30337SRick Edgecombe 
239*81f30337SRick Edgecombe 	return !segv_triggered;
240*81f30337SRick Edgecombe }
241*81f30337SRick Edgecombe 
242*81f30337SRick Edgecombe /* Gup test state */
243*81f30337SRick Edgecombe #define MAGIC_VAL 0x12345678
244*81f30337SRick Edgecombe bool is_shstk_access;
245*81f30337SRick Edgecombe void *shstk_ptr;
246*81f30337SRick Edgecombe int fd;
247*81f30337SRick Edgecombe 
248*81f30337SRick Edgecombe void reset_test_shstk(void *addr)
249*81f30337SRick Edgecombe {
250*81f30337SRick Edgecombe 	if (shstk_ptr)
251*81f30337SRick Edgecombe 		free_shstk(shstk_ptr);
252*81f30337SRick Edgecombe 	shstk_ptr = create_shstk(addr);
253*81f30337SRick Edgecombe }
254*81f30337SRick Edgecombe 
255*81f30337SRick Edgecombe void test_access_fix_handler(int signum, siginfo_t *si, void *uc)
256*81f30337SRick Edgecombe {
257*81f30337SRick Edgecombe 	printf("[INFO]\tViolation from %s\n", is_shstk_access ? "shstk access" : "normal write");
258*81f30337SRick Edgecombe 
259*81f30337SRick Edgecombe 	segv_triggered = true;
260*81f30337SRick Edgecombe 
261*81f30337SRick Edgecombe 	/* Fix shadow stack */
262*81f30337SRick Edgecombe 	if (is_shstk_access) {
263*81f30337SRick Edgecombe 		reset_test_shstk(shstk_ptr);
264*81f30337SRick Edgecombe 		return;
265*81f30337SRick Edgecombe 	}
266*81f30337SRick Edgecombe 
267*81f30337SRick Edgecombe 	free_shstk(shstk_ptr);
268*81f30337SRick Edgecombe 	create_normal_mem(shstk_ptr);
269*81f30337SRick Edgecombe }
270*81f30337SRick Edgecombe 
271*81f30337SRick Edgecombe bool test_shstk_access(void *ptr)
272*81f30337SRick Edgecombe {
273*81f30337SRick Edgecombe 	is_shstk_access = true;
274*81f30337SRick Edgecombe 	segv_triggered = false;
275*81f30337SRick Edgecombe 	write_shstk(ptr, MAGIC_VAL);
276*81f30337SRick Edgecombe 
277*81f30337SRick Edgecombe 	asm volatile("" : : : "memory");
278*81f30337SRick Edgecombe 
279*81f30337SRick Edgecombe 	return segv_triggered;
280*81f30337SRick Edgecombe }
281*81f30337SRick Edgecombe 
282*81f30337SRick Edgecombe bool test_write_access(void *ptr)
283*81f30337SRick Edgecombe {
284*81f30337SRick Edgecombe 	is_shstk_access = false;
285*81f30337SRick Edgecombe 	segv_triggered = false;
286*81f30337SRick Edgecombe 	*(unsigned long *)ptr = MAGIC_VAL;
287*81f30337SRick Edgecombe 
288*81f30337SRick Edgecombe 	asm volatile("" : : : "memory");
289*81f30337SRick Edgecombe 
290*81f30337SRick Edgecombe 	return segv_triggered;
291*81f30337SRick Edgecombe }
292*81f30337SRick Edgecombe 
293*81f30337SRick Edgecombe bool gup_write(void *ptr)
294*81f30337SRick Edgecombe {
295*81f30337SRick Edgecombe 	unsigned long val;
296*81f30337SRick Edgecombe 
297*81f30337SRick Edgecombe 	lseek(fd, (unsigned long)ptr, SEEK_SET);
298*81f30337SRick Edgecombe 	if (write(fd, &val, sizeof(val)) < 0)
299*81f30337SRick Edgecombe 		return 1;
300*81f30337SRick Edgecombe 
301*81f30337SRick Edgecombe 	return 0;
302*81f30337SRick Edgecombe }
303*81f30337SRick Edgecombe 
304*81f30337SRick Edgecombe bool gup_read(void *ptr)
305*81f30337SRick Edgecombe {
306*81f30337SRick Edgecombe 	unsigned long val;
307*81f30337SRick Edgecombe 
308*81f30337SRick Edgecombe 	lseek(fd, (unsigned long)ptr, SEEK_SET);
309*81f30337SRick Edgecombe 	if (read(fd, &val, sizeof(val)) < 0)
310*81f30337SRick Edgecombe 		return 1;
311*81f30337SRick Edgecombe 
312*81f30337SRick Edgecombe 	return 0;
313*81f30337SRick Edgecombe }
314*81f30337SRick Edgecombe 
315*81f30337SRick Edgecombe int test_gup(void)
316*81f30337SRick Edgecombe {
317*81f30337SRick Edgecombe 	struct sigaction sa = {};
318*81f30337SRick Edgecombe 	int status;
319*81f30337SRick Edgecombe 	pid_t pid;
320*81f30337SRick Edgecombe 
321*81f30337SRick Edgecombe 	sa.sa_sigaction = test_access_fix_handler;
322*81f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
323*81f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
324*81f30337SRick Edgecombe 		return 1;
325*81f30337SRick Edgecombe 
326*81f30337SRick Edgecombe 	segv_triggered = false;
327*81f30337SRick Edgecombe 
328*81f30337SRick Edgecombe 	fd = open("/proc/self/mem", O_RDWR);
329*81f30337SRick Edgecombe 	if (fd == -1)
330*81f30337SRick Edgecombe 		return 1;
331*81f30337SRick Edgecombe 
332*81f30337SRick Edgecombe 	reset_test_shstk(0);
333*81f30337SRick Edgecombe 	if (gup_read(shstk_ptr))
334*81f30337SRick Edgecombe 		return 1;
335*81f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr))
336*81f30337SRick Edgecombe 		return 1;
337*81f30337SRick Edgecombe 	printf("[INFO]\tGup read -> shstk access success\n");
338*81f30337SRick Edgecombe 
339*81f30337SRick Edgecombe 	reset_test_shstk(0);
340*81f30337SRick Edgecombe 	if (gup_write(shstk_ptr))
341*81f30337SRick Edgecombe 		return 1;
342*81f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr))
343*81f30337SRick Edgecombe 		return 1;
344*81f30337SRick Edgecombe 	printf("[INFO]\tGup write -> shstk access success\n");
345*81f30337SRick Edgecombe 
346*81f30337SRick Edgecombe 	reset_test_shstk(0);
347*81f30337SRick Edgecombe 	if (gup_read(shstk_ptr))
348*81f30337SRick Edgecombe 		return 1;
349*81f30337SRick Edgecombe 	if (!test_write_access(shstk_ptr))
350*81f30337SRick Edgecombe 		return 1;
351*81f30337SRick Edgecombe 	printf("[INFO]\tGup read -> write access success\n");
352*81f30337SRick Edgecombe 
353*81f30337SRick Edgecombe 	reset_test_shstk(0);
354*81f30337SRick Edgecombe 	if (gup_write(shstk_ptr))
355*81f30337SRick Edgecombe 		return 1;
356*81f30337SRick Edgecombe 	if (!test_write_access(shstk_ptr))
357*81f30337SRick Edgecombe 		return 1;
358*81f30337SRick Edgecombe 	printf("[INFO]\tGup write -> write access success\n");
359*81f30337SRick Edgecombe 
360*81f30337SRick Edgecombe 	close(fd);
361*81f30337SRick Edgecombe 
362*81f30337SRick Edgecombe 	/* COW/gup test */
363*81f30337SRick Edgecombe 	reset_test_shstk(0);
364*81f30337SRick Edgecombe 	pid = fork();
365*81f30337SRick Edgecombe 	if (!pid) {
366*81f30337SRick Edgecombe 		fd = open("/proc/self/mem", O_RDWR);
367*81f30337SRick Edgecombe 		if (fd == -1)
368*81f30337SRick Edgecombe 			exit(1);
369*81f30337SRick Edgecombe 
370*81f30337SRick Edgecombe 		if (gup_write(shstk_ptr)) {
371*81f30337SRick Edgecombe 			close(fd);
372*81f30337SRick Edgecombe 			exit(1);
373*81f30337SRick Edgecombe 		}
374*81f30337SRick Edgecombe 		close(fd);
375*81f30337SRick Edgecombe 		exit(0);
376*81f30337SRick Edgecombe 	}
377*81f30337SRick Edgecombe 	waitpid(pid, &status, 0);
378*81f30337SRick Edgecombe 	if (WEXITSTATUS(status)) {
379*81f30337SRick Edgecombe 		printf("[FAIL]\tWrite in child failed\n");
380*81f30337SRick Edgecombe 		return 1;
381*81f30337SRick Edgecombe 	}
382*81f30337SRick Edgecombe 	if (*(unsigned long *)shstk_ptr == MAGIC_VAL) {
383*81f30337SRick Edgecombe 		printf("[FAIL]\tWrite in child wrote through to shared memory\n");
384*81f30337SRick Edgecombe 		return 1;
385*81f30337SRick Edgecombe 	}
386*81f30337SRick Edgecombe 
387*81f30337SRick Edgecombe 	printf("[INFO]\tCow gup write -> write access success\n");
388*81f30337SRick Edgecombe 
389*81f30337SRick Edgecombe 	free_shstk(shstk_ptr);
390*81f30337SRick Edgecombe 
391*81f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
392*81f30337SRick Edgecombe 
393*81f30337SRick Edgecombe 	printf("[OK]\tShadow gup test\n");
394*81f30337SRick Edgecombe 
395*81f30337SRick Edgecombe 	return 0;
396*81f30337SRick Edgecombe }
397*81f30337SRick Edgecombe 
398*81f30337SRick Edgecombe int test_mprotect(void)
399*81f30337SRick Edgecombe {
400*81f30337SRick Edgecombe 	struct sigaction sa = {};
401*81f30337SRick Edgecombe 
402*81f30337SRick Edgecombe 	sa.sa_sigaction = test_access_fix_handler;
403*81f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
404*81f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
405*81f30337SRick Edgecombe 		return 1;
406*81f30337SRick Edgecombe 
407*81f30337SRick Edgecombe 	segv_triggered = false;
408*81f30337SRick Edgecombe 
409*81f30337SRick Edgecombe 	/* mprotect a shadow stack as read only */
410*81f30337SRick Edgecombe 	reset_test_shstk(0);
411*81f30337SRick Edgecombe 	if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {
412*81f30337SRick Edgecombe 		printf("[FAIL]\tmprotect(PROT_READ) failed\n");
413*81f30337SRick Edgecombe 		return 1;
414*81f30337SRick Edgecombe 	}
415*81f30337SRick Edgecombe 
416*81f30337SRick Edgecombe 	/* try to wrss it and fail */
417*81f30337SRick Edgecombe 	if (!test_shstk_access(shstk_ptr)) {
418*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack access to read-only memory succeeded\n");
419*81f30337SRick Edgecombe 		return 1;
420*81f30337SRick Edgecombe 	}
421*81f30337SRick Edgecombe 
422*81f30337SRick Edgecombe 	/*
423*81f30337SRick Edgecombe 	 * The shadow stack was reset above to resolve the fault, make the new one
424*81f30337SRick Edgecombe 	 * read-only.
425*81f30337SRick Edgecombe 	 */
426*81f30337SRick Edgecombe 	if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {
427*81f30337SRick Edgecombe 		printf("[FAIL]\tmprotect(PROT_READ) failed\n");
428*81f30337SRick Edgecombe 		return 1;
429*81f30337SRick Edgecombe 	}
430*81f30337SRick Edgecombe 
431*81f30337SRick Edgecombe 	/* then back to writable */
432*81f30337SRick Edgecombe 	if (mprotect(shstk_ptr, SS_SIZE, PROT_WRITE | PROT_READ) < 0) {
433*81f30337SRick Edgecombe 		printf("[FAIL]\tmprotect(PROT_WRITE) failed\n");
434*81f30337SRick Edgecombe 		return 1;
435*81f30337SRick Edgecombe 	}
436*81f30337SRick Edgecombe 
437*81f30337SRick Edgecombe 	/* then wrss to it and succeed */
438*81f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr)) {
439*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack access to mprotect() writable memory failed\n");
440*81f30337SRick Edgecombe 		return 1;
441*81f30337SRick Edgecombe 	}
442*81f30337SRick Edgecombe 
443*81f30337SRick Edgecombe 	free_shstk(shstk_ptr);
444*81f30337SRick Edgecombe 
445*81f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
446*81f30337SRick Edgecombe 
447*81f30337SRick Edgecombe 	printf("[OK]\tmprotect() test\n");
448*81f30337SRick Edgecombe 
449*81f30337SRick Edgecombe 	return 0;
450*81f30337SRick Edgecombe }
451*81f30337SRick Edgecombe 
452*81f30337SRick Edgecombe char zero[4096];
453*81f30337SRick Edgecombe 
454*81f30337SRick Edgecombe static void *uffd_thread(void *arg)
455*81f30337SRick Edgecombe {
456*81f30337SRick Edgecombe 	struct uffdio_copy req;
457*81f30337SRick Edgecombe 	int uffd = *(int *)arg;
458*81f30337SRick Edgecombe 	struct uffd_msg msg;
459*81f30337SRick Edgecombe 	int ret;
460*81f30337SRick Edgecombe 
461*81f30337SRick Edgecombe 	while (1) {
462*81f30337SRick Edgecombe 		ret = read(uffd, &msg, sizeof(msg));
463*81f30337SRick Edgecombe 		if (ret > 0)
464*81f30337SRick Edgecombe 			break;
465*81f30337SRick Edgecombe 		else if (errno == EAGAIN)
466*81f30337SRick Edgecombe 			continue;
467*81f30337SRick Edgecombe 		return (void *)1;
468*81f30337SRick Edgecombe 	}
469*81f30337SRick Edgecombe 
470*81f30337SRick Edgecombe 	req.dst = msg.arg.pagefault.address;
471*81f30337SRick Edgecombe 	req.src = (__u64)zero;
472*81f30337SRick Edgecombe 	req.len = 4096;
473*81f30337SRick Edgecombe 	req.mode = 0;
474*81f30337SRick Edgecombe 
475*81f30337SRick Edgecombe 	if (ioctl(uffd, UFFDIO_COPY, &req))
476*81f30337SRick Edgecombe 		return (void *)1;
477*81f30337SRick Edgecombe 
478*81f30337SRick Edgecombe 	return (void *)0;
479*81f30337SRick Edgecombe }
480*81f30337SRick Edgecombe 
481*81f30337SRick Edgecombe int test_userfaultfd(void)
482*81f30337SRick Edgecombe {
483*81f30337SRick Edgecombe 	struct uffdio_register uffdio_register;
484*81f30337SRick Edgecombe 	struct uffdio_api uffdio_api;
485*81f30337SRick Edgecombe 	struct sigaction sa = {};
486*81f30337SRick Edgecombe 	pthread_t thread;
487*81f30337SRick Edgecombe 	void *res;
488*81f30337SRick Edgecombe 	int uffd;
489*81f30337SRick Edgecombe 
490*81f30337SRick Edgecombe 	sa.sa_sigaction = test_access_fix_handler;
491*81f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
492*81f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
493*81f30337SRick Edgecombe 		return 1;
494*81f30337SRick Edgecombe 
495*81f30337SRick Edgecombe 	uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
496*81f30337SRick Edgecombe 	if (uffd < 0) {
497*81f30337SRick Edgecombe 		printf("[SKIP]\tUserfaultfd unavailable.\n");
498*81f30337SRick Edgecombe 		return 0;
499*81f30337SRick Edgecombe 	}
500*81f30337SRick Edgecombe 
501*81f30337SRick Edgecombe 	reset_test_shstk(0);
502*81f30337SRick Edgecombe 
503*81f30337SRick Edgecombe 	uffdio_api.api = UFFD_API;
504*81f30337SRick Edgecombe 	uffdio_api.features = 0;
505*81f30337SRick Edgecombe 	if (ioctl(uffd, UFFDIO_API, &uffdio_api))
506*81f30337SRick Edgecombe 		goto err;
507*81f30337SRick Edgecombe 
508*81f30337SRick Edgecombe 	uffdio_register.range.start = (__u64)shstk_ptr;
509*81f30337SRick Edgecombe 	uffdio_register.range.len = 4096;
510*81f30337SRick Edgecombe 	uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
511*81f30337SRick Edgecombe 	if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
512*81f30337SRick Edgecombe 		goto err;
513*81f30337SRick Edgecombe 
514*81f30337SRick Edgecombe 	if (pthread_create(&thread, NULL, &uffd_thread, &uffd))
515*81f30337SRick Edgecombe 		goto err;
516*81f30337SRick Edgecombe 
517*81f30337SRick Edgecombe 	reset_shstk(shstk_ptr);
518*81f30337SRick Edgecombe 	test_shstk_access(shstk_ptr);
519*81f30337SRick Edgecombe 
520*81f30337SRick Edgecombe 	if (pthread_join(thread, &res))
521*81f30337SRick Edgecombe 		goto err;
522*81f30337SRick Edgecombe 
523*81f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr))
524*81f30337SRick Edgecombe 		goto err;
525*81f30337SRick Edgecombe 
526*81f30337SRick Edgecombe 	free_shstk(shstk_ptr);
527*81f30337SRick Edgecombe 
528*81f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
529*81f30337SRick Edgecombe 
530*81f30337SRick Edgecombe 	if (!res)
531*81f30337SRick Edgecombe 		printf("[OK]\tUserfaultfd test\n");
532*81f30337SRick Edgecombe 	return !!res;
533*81f30337SRick Edgecombe err:
534*81f30337SRick Edgecombe 	free_shstk(shstk_ptr);
535*81f30337SRick Edgecombe 	close(uffd);
536*81f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
537*81f30337SRick Edgecombe 	return 1;
538*81f30337SRick Edgecombe }
539*81f30337SRick Edgecombe 
540*81f30337SRick Edgecombe /* Simple linked list for keeping track of mappings in test_guard_gap() */
541*81f30337SRick Edgecombe struct node {
542*81f30337SRick Edgecombe 	struct node *next;
543*81f30337SRick Edgecombe 	void *mapping;
544*81f30337SRick Edgecombe };
545*81f30337SRick Edgecombe 
546*81f30337SRick Edgecombe /*
547*81f30337SRick Edgecombe  * This tests whether mmap will place other mappings in a shadow stack's guard
548*81f30337SRick Edgecombe  * gap. The steps are:
549*81f30337SRick Edgecombe  *   1. Finds an empty place by mapping and unmapping something.
550*81f30337SRick Edgecombe  *   2. Map a shadow stack in the middle of the known empty area.
551*81f30337SRick Edgecombe  *   3. Map a bunch of PAGE_SIZE mappings. These will use the search down
552*81f30337SRick Edgecombe  *      direction, filling any gaps until it encounters the shadow stack's
553*81f30337SRick Edgecombe  *      guard gap.
554*81f30337SRick Edgecombe  *   4. When a mapping lands below the shadow stack from step 2, then all
555*81f30337SRick Edgecombe  *      of the above gaps are filled. The search down algorithm will have
556*81f30337SRick Edgecombe  *      looked at the shadow stack gaps.
557*81f30337SRick Edgecombe  *   5. See if it landed in the gap.
558*81f30337SRick Edgecombe  */
559*81f30337SRick Edgecombe int test_guard_gap(void)
560*81f30337SRick Edgecombe {
561*81f30337SRick Edgecombe 	void *free_area, *shstk, *test_map = (void *)0xFFFFFFFFFFFFFFFF;
562*81f30337SRick Edgecombe 	struct node *head = NULL, *cur;
563*81f30337SRick Edgecombe 
564*81f30337SRick Edgecombe 	free_area = mmap(0, SS_SIZE * 3, PROT_READ | PROT_WRITE,
565*81f30337SRick Edgecombe 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
566*81f30337SRick Edgecombe 	munmap(free_area, SS_SIZE * 3);
567*81f30337SRick Edgecombe 
568*81f30337SRick Edgecombe 	shstk = create_shstk(free_area + SS_SIZE);
569*81f30337SRick Edgecombe 	if (shstk == MAP_FAILED)
570*81f30337SRick Edgecombe 		return 1;
571*81f30337SRick Edgecombe 
572*81f30337SRick Edgecombe 	while (test_map > shstk) {
573*81f30337SRick Edgecombe 		test_map = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE,
574*81f30337SRick Edgecombe 				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
575*81f30337SRick Edgecombe 		if (test_map == MAP_FAILED)
576*81f30337SRick Edgecombe 			return 1;
577*81f30337SRick Edgecombe 		cur = malloc(sizeof(*cur));
578*81f30337SRick Edgecombe 		cur->mapping = test_map;
579*81f30337SRick Edgecombe 
580*81f30337SRick Edgecombe 		cur->next = head;
581*81f30337SRick Edgecombe 		head = cur;
582*81f30337SRick Edgecombe 	}
583*81f30337SRick Edgecombe 
584*81f30337SRick Edgecombe 	while (head) {
585*81f30337SRick Edgecombe 		cur = head;
586*81f30337SRick Edgecombe 		head = cur->next;
587*81f30337SRick Edgecombe 		munmap(cur->mapping, PAGE_SIZE);
588*81f30337SRick Edgecombe 		free(cur);
589*81f30337SRick Edgecombe 	}
590*81f30337SRick Edgecombe 
591*81f30337SRick Edgecombe 	free_shstk(shstk);
592*81f30337SRick Edgecombe 
593*81f30337SRick Edgecombe 	if (shstk - test_map - PAGE_SIZE != PAGE_SIZE)
594*81f30337SRick Edgecombe 		return 1;
595*81f30337SRick Edgecombe 
596*81f30337SRick Edgecombe 	printf("[OK]\tGuard gap test\n");
597*81f30337SRick Edgecombe 
598*81f30337SRick Edgecombe 	return 0;
599*81f30337SRick Edgecombe }
600*81f30337SRick Edgecombe 
601*81f30337SRick Edgecombe /*
602*81f30337SRick Edgecombe  * Too complicated to pull it out of the 32 bit header, but also get the
603*81f30337SRick Edgecombe  * 64 bit one needed above. Just define a copy here.
604*81f30337SRick Edgecombe  */
605*81f30337SRick Edgecombe #define __NR_compat_sigaction 67
606*81f30337SRick Edgecombe 
607*81f30337SRick Edgecombe /*
608*81f30337SRick Edgecombe  * Call 32 bit signal handler to get 32 bit signals ABI. Make sure
609*81f30337SRick Edgecombe  * to push the registers that will get clobbered.
610*81f30337SRick Edgecombe  */
611*81f30337SRick Edgecombe int sigaction32(int signum, const struct sigaction *restrict act,
612*81f30337SRick Edgecombe 		struct sigaction *restrict oldact)
613*81f30337SRick Edgecombe {
614*81f30337SRick Edgecombe 	register long syscall_reg asm("eax") = __NR_compat_sigaction;
615*81f30337SRick Edgecombe 	register long signum_reg asm("ebx") = signum;
616*81f30337SRick Edgecombe 	register long act_reg asm("ecx") = (long)act;
617*81f30337SRick Edgecombe 	register long oldact_reg asm("edx") = (long)oldact;
618*81f30337SRick Edgecombe 	int ret = 0;
619*81f30337SRick Edgecombe 
620*81f30337SRick Edgecombe 	asm volatile ("int $0x80;"
621*81f30337SRick Edgecombe 		      : "=a"(ret), "=m"(oldact)
622*81f30337SRick Edgecombe 		      : "r"(syscall_reg), "r"(signum_reg), "r"(act_reg),
623*81f30337SRick Edgecombe 			"r"(oldact_reg)
624*81f30337SRick Edgecombe 		      : "r8", "r9", "r10", "r11"
625*81f30337SRick Edgecombe 		     );
626*81f30337SRick Edgecombe 
627*81f30337SRick Edgecombe 	return ret;
628*81f30337SRick Edgecombe }
629*81f30337SRick Edgecombe 
630*81f30337SRick Edgecombe sigjmp_buf jmp_buffer;
631*81f30337SRick Edgecombe 
632*81f30337SRick Edgecombe void segv_gp_handler(int signum, siginfo_t *si, void *uc)
633*81f30337SRick Edgecombe {
634*81f30337SRick Edgecombe 	segv_triggered = true;
635*81f30337SRick Edgecombe 
636*81f30337SRick Edgecombe 	/*
637*81f30337SRick Edgecombe 	 * To work with old glibc, this can't rely on siglongjmp working with
638*81f30337SRick Edgecombe 	 * shadow stack enabled, so disable shadow stack before siglongjmp().
639*81f30337SRick Edgecombe 	 */
640*81f30337SRick Edgecombe 	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
641*81f30337SRick Edgecombe 	siglongjmp(jmp_buffer, -1);
642*81f30337SRick Edgecombe }
643*81f30337SRick Edgecombe 
644*81f30337SRick Edgecombe /*
645*81f30337SRick Edgecombe  * Transition to 32 bit mode and check that a #GP triggers a segfault.
646*81f30337SRick Edgecombe  */
647*81f30337SRick Edgecombe int test_32bit(void)
648*81f30337SRick Edgecombe {
649*81f30337SRick Edgecombe 	struct sigaction sa = {};
650*81f30337SRick Edgecombe 	struct sigaction *sa32;
651*81f30337SRick Edgecombe 
652*81f30337SRick Edgecombe 	/* Create sigaction in 32 bit address range */
653*81f30337SRick Edgecombe 	sa32 = mmap(0, 4096, PROT_READ | PROT_WRITE,
654*81f30337SRick Edgecombe 		    MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
655*81f30337SRick Edgecombe 	sa32->sa_flags = SA_SIGINFO;
656*81f30337SRick Edgecombe 
657*81f30337SRick Edgecombe 	sa.sa_sigaction = segv_gp_handler;
658*81f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
659*81f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
660*81f30337SRick Edgecombe 		return 1;
661*81f30337SRick Edgecombe 
662*81f30337SRick Edgecombe 
663*81f30337SRick Edgecombe 	segv_triggered = false;
664*81f30337SRick Edgecombe 
665*81f30337SRick Edgecombe 	/* Make sure segv_triggered is set before triggering the #GP */
666*81f30337SRick Edgecombe 	asm volatile("" : : : "memory");
667*81f30337SRick Edgecombe 
668*81f30337SRick Edgecombe 	/*
669*81f30337SRick Edgecombe 	 * Set handler to somewhere in 32 bit address space
670*81f30337SRick Edgecombe 	 */
671*81f30337SRick Edgecombe 	sa32->sa_handler = (void *)sa32;
672*81f30337SRick Edgecombe 	if (sigaction32(SIGUSR1, sa32, NULL))
673*81f30337SRick Edgecombe 		return 1;
674*81f30337SRick Edgecombe 
675*81f30337SRick Edgecombe 	if (!sigsetjmp(jmp_buffer, 1))
676*81f30337SRick Edgecombe 		raise(SIGUSR1);
677*81f30337SRick Edgecombe 
678*81f30337SRick Edgecombe 	if (segv_triggered)
679*81f30337SRick Edgecombe 		printf("[OK]\t32 bit test\n");
680*81f30337SRick Edgecombe 
681*81f30337SRick Edgecombe 	return !segv_triggered;
682*81f30337SRick Edgecombe }
683*81f30337SRick Edgecombe 
684*81f30337SRick Edgecombe void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)
685*81f30337SRick Edgecombe {
686*81f30337SRick Edgecombe 	/* The SSP adjustment caused a segfault. */
687*81f30337SRick Edgecombe 	exit(0);
688*81f30337SRick Edgecombe }
689*81f30337SRick Edgecombe 
690*81f30337SRick Edgecombe int test_ptrace(void)
691*81f30337SRick Edgecombe {
692*81f30337SRick Edgecombe 	unsigned long saved_ssp, ssp = 0;
693*81f30337SRick Edgecombe 	struct sigaction sa= {};
694*81f30337SRick Edgecombe 	struct iovec iov;
695*81f30337SRick Edgecombe 	int status;
696*81f30337SRick Edgecombe 	int pid;
697*81f30337SRick Edgecombe 
698*81f30337SRick Edgecombe 	iov.iov_base = &ssp;
699*81f30337SRick Edgecombe 	iov.iov_len = sizeof(ssp);
700*81f30337SRick Edgecombe 
701*81f30337SRick Edgecombe 	pid = fork();
702*81f30337SRick Edgecombe 	if (!pid) {
703*81f30337SRick Edgecombe 		ssp = get_ssp();
704*81f30337SRick Edgecombe 
705*81f30337SRick Edgecombe 		sa.sa_sigaction = segv_handler_ptrace;
706*81f30337SRick Edgecombe 		sa.sa_flags = SA_SIGINFO;
707*81f30337SRick Edgecombe 		if (sigaction(SIGSEGV, &sa, NULL))
708*81f30337SRick Edgecombe 			return 1;
709*81f30337SRick Edgecombe 
710*81f30337SRick Edgecombe 		ptrace(PTRACE_TRACEME, NULL, NULL, NULL);
711*81f30337SRick Edgecombe 		/*
712*81f30337SRick Edgecombe 		 * The parent will tweak the SSP and return from this function
713*81f30337SRick Edgecombe 		 * will #CP.
714*81f30337SRick Edgecombe 		 */
715*81f30337SRick Edgecombe 		raise(SIGTRAP);
716*81f30337SRick Edgecombe 
717*81f30337SRick Edgecombe 		exit(1);
718*81f30337SRick Edgecombe 	}
719*81f30337SRick Edgecombe 
720*81f30337SRick Edgecombe 	while (waitpid(pid, &status, 0) != -1 && WSTOPSIG(status) != SIGTRAP);
721*81f30337SRick Edgecombe 
722*81f30337SRick Edgecombe 	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_SHSTK, &iov)) {
723*81f30337SRick Edgecombe 		printf("[INFO]\tFailed to PTRACE_GETREGS\n");
724*81f30337SRick Edgecombe 		goto out_kill;
725*81f30337SRick Edgecombe 	}
726*81f30337SRick Edgecombe 
727*81f30337SRick Edgecombe 	if (!ssp) {
728*81f30337SRick Edgecombe 		printf("[INFO]\tPtrace child SSP was 0\n");
729*81f30337SRick Edgecombe 		goto out_kill;
730*81f30337SRick Edgecombe 	}
731*81f30337SRick Edgecombe 
732*81f30337SRick Edgecombe 	saved_ssp = ssp;
733*81f30337SRick Edgecombe 
734*81f30337SRick Edgecombe 	iov.iov_len = 0;
735*81f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
736*81f30337SRick Edgecombe 		printf("[INFO]\tToo small size accepted via PTRACE_SETREGS\n");
737*81f30337SRick Edgecombe 		goto out_kill;
738*81f30337SRick Edgecombe 	}
739*81f30337SRick Edgecombe 
740*81f30337SRick Edgecombe 	iov.iov_len = sizeof(ssp) + 1;
741*81f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
742*81f30337SRick Edgecombe 		printf("[INFO]\tToo large size accepted via PTRACE_SETREGS\n");
743*81f30337SRick Edgecombe 		goto out_kill;
744*81f30337SRick Edgecombe 	}
745*81f30337SRick Edgecombe 
746*81f30337SRick Edgecombe 	ssp += 1;
747*81f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
748*81f30337SRick Edgecombe 		printf("[INFO]\tUnaligned SSP written via PTRACE_SETREGS\n");
749*81f30337SRick Edgecombe 		goto out_kill;
750*81f30337SRick Edgecombe 	}
751*81f30337SRick Edgecombe 
752*81f30337SRick Edgecombe 	ssp = 0xFFFFFFFFFFFF0000;
753*81f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
754*81f30337SRick Edgecombe 		printf("[INFO]\tKernel range SSP written via PTRACE_SETREGS\n");
755*81f30337SRick Edgecombe 		goto out_kill;
756*81f30337SRick Edgecombe 	}
757*81f30337SRick Edgecombe 
758*81f30337SRick Edgecombe 	/*
759*81f30337SRick Edgecombe 	 * Tweak the SSP so the child with #CP when it resumes and returns
760*81f30337SRick Edgecombe 	 * from raise()
761*81f30337SRick Edgecombe 	 */
762*81f30337SRick Edgecombe 	ssp = saved_ssp + 8;
763*81f30337SRick Edgecombe 	iov.iov_len = sizeof(ssp);
764*81f30337SRick Edgecombe 	if (ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
765*81f30337SRick Edgecombe 		printf("[INFO]\tFailed to PTRACE_SETREGS\n");
766*81f30337SRick Edgecombe 		goto out_kill;
767*81f30337SRick Edgecombe 	}
768*81f30337SRick Edgecombe 
769*81f30337SRick Edgecombe 	if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
770*81f30337SRick Edgecombe 		printf("[INFO]\tFailed to PTRACE_DETACH\n");
771*81f30337SRick Edgecombe 		goto out_kill;
772*81f30337SRick Edgecombe 	}
773*81f30337SRick Edgecombe 
774*81f30337SRick Edgecombe 	waitpid(pid, &status, 0);
775*81f30337SRick Edgecombe 	if (WEXITSTATUS(status))
776*81f30337SRick Edgecombe 		return 1;
777*81f30337SRick Edgecombe 
778*81f30337SRick Edgecombe 	printf("[OK]\tPtrace test\n");
779*81f30337SRick Edgecombe 	return 0;
780*81f30337SRick Edgecombe 
781*81f30337SRick Edgecombe out_kill:
782*81f30337SRick Edgecombe 	kill(pid, SIGKILL);
783*81f30337SRick Edgecombe 	return 1;
784*81f30337SRick Edgecombe }
785*81f30337SRick Edgecombe 
786*81f30337SRick Edgecombe int main(int argc, char *argv[])
787*81f30337SRick Edgecombe {
788*81f30337SRick Edgecombe 	int ret = 0;
789*81f30337SRick Edgecombe 
790*81f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {
791*81f30337SRick Edgecombe 		printf("[SKIP]\tCould not enable Shadow stack\n");
792*81f30337SRick Edgecombe 		return 1;
793*81f30337SRick Edgecombe 	}
794*81f30337SRick Edgecombe 
795*81f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {
796*81f30337SRick Edgecombe 		ret = 1;
797*81f30337SRick Edgecombe 		printf("[FAIL]\tDisabling shadow stack failed\n");
798*81f30337SRick Edgecombe 	}
799*81f30337SRick Edgecombe 
800*81f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {
801*81f30337SRick Edgecombe 		printf("[SKIP]\tCould not re-enable Shadow stack\n");
802*81f30337SRick Edgecombe 		return 1;
803*81f30337SRick Edgecombe 	}
804*81f30337SRick Edgecombe 
805*81f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_WRSS)) {
806*81f30337SRick Edgecombe 		printf("[SKIP]\tCould not enable WRSS\n");
807*81f30337SRick Edgecombe 		ret = 1;
808*81f30337SRick Edgecombe 		goto out;
809*81f30337SRick Edgecombe 	}
810*81f30337SRick Edgecombe 
811*81f30337SRick Edgecombe 	/* Should have succeeded if here, but this is a test, so double check. */
812*81f30337SRick Edgecombe 	if (!get_ssp()) {
813*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack disabled\n");
814*81f30337SRick Edgecombe 		return 1;
815*81f30337SRick Edgecombe 	}
816*81f30337SRick Edgecombe 
817*81f30337SRick Edgecombe 	if (test_shstk_pivot()) {
818*81f30337SRick Edgecombe 		ret = 1;
819*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack pivot\n");
820*81f30337SRick Edgecombe 		goto out;
821*81f30337SRick Edgecombe 	}
822*81f30337SRick Edgecombe 
823*81f30337SRick Edgecombe 	if (test_shstk_faults()) {
824*81f30337SRick Edgecombe 		ret = 1;
825*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack fault test\n");
826*81f30337SRick Edgecombe 		goto out;
827*81f30337SRick Edgecombe 	}
828*81f30337SRick Edgecombe 
829*81f30337SRick Edgecombe 	if (test_shstk_violation()) {
830*81f30337SRick Edgecombe 		ret = 1;
831*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack violation test\n");
832*81f30337SRick Edgecombe 		goto out;
833*81f30337SRick Edgecombe 	}
834*81f30337SRick Edgecombe 
835*81f30337SRick Edgecombe 	if (test_gup()) {
836*81f30337SRick Edgecombe 		ret = 1;
837*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow shadow stack gup\n");
838*81f30337SRick Edgecombe 		goto out;
839*81f30337SRick Edgecombe 	}
840*81f30337SRick Edgecombe 
841*81f30337SRick Edgecombe 	if (test_mprotect()) {
842*81f30337SRick Edgecombe 		ret = 1;
843*81f30337SRick Edgecombe 		printf("[FAIL]\tShadow shadow mprotect test\n");
844*81f30337SRick Edgecombe 		goto out;
845*81f30337SRick Edgecombe 	}
846*81f30337SRick Edgecombe 
847*81f30337SRick Edgecombe 	if (test_userfaultfd()) {
848*81f30337SRick Edgecombe 		ret = 1;
849*81f30337SRick Edgecombe 		printf("[FAIL]\tUserfaultfd test\n");
850*81f30337SRick Edgecombe 		goto out;
851*81f30337SRick Edgecombe 	}
852*81f30337SRick Edgecombe 
853*81f30337SRick Edgecombe 	if (test_guard_gap()) {
854*81f30337SRick Edgecombe 		ret = 1;
855*81f30337SRick Edgecombe 		printf("[FAIL]\tGuard gap test\n");
856*81f30337SRick Edgecombe 		goto out;
857*81f30337SRick Edgecombe 	}
858*81f30337SRick Edgecombe 
859*81f30337SRick Edgecombe 	if (test_ptrace()) {
860*81f30337SRick Edgecombe 		ret = 1;
861*81f30337SRick Edgecombe 		printf("[FAIL]\tptrace test\n");
862*81f30337SRick Edgecombe 	}
863*81f30337SRick Edgecombe 
864*81f30337SRick Edgecombe 	if (test_32bit()) {
865*81f30337SRick Edgecombe 		ret = 1;
866*81f30337SRick Edgecombe 		printf("[FAIL]\t32 bit test\n");
867*81f30337SRick Edgecombe 		goto out;
868*81f30337SRick Edgecombe 	}
869*81f30337SRick Edgecombe 
870*81f30337SRick Edgecombe 	return ret;
871*81f30337SRick Edgecombe 
872*81f30337SRick Edgecombe out:
873*81f30337SRick Edgecombe 	/*
874*81f30337SRick Edgecombe 	 * Disable shadow stack before the function returns, or there will be a
875*81f30337SRick Edgecombe 	 * shadow stack violation.
876*81f30337SRick Edgecombe 	 */
877*81f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {
878*81f30337SRick Edgecombe 		ret = 1;
879*81f30337SRick Edgecombe 		printf("[FAIL]\tDisabling shadow stack failed\n");
880*81f30337SRick Edgecombe 	}
881*81f30337SRick Edgecombe 
882*81f30337SRick Edgecombe 	return ret;
883*81f30337SRick Edgecombe }
884*81f30337SRick Edgecombe #endif
885