xref: /linux/tools/testing/selftests/x86/test_shadow_stack.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
181f30337SRick Edgecombe // SPDX-License-Identifier: GPL-2.0
281f30337SRick Edgecombe /*
381f30337SRick Edgecombe  * This program test's basic kernel shadow stack support. It enables shadow
481f30337SRick Edgecombe  * stack manual via the arch_prctl(), instead of relying on glibc. It's
581f30337SRick Edgecombe  * Makefile doesn't compile with shadow stack support, so it doesn't rely on
681f30337SRick Edgecombe  * any particular glibc. As a result it can't do any operations that require
781f30337SRick Edgecombe  * special glibc shadow stack support (longjmp(), swapcontext(), etc). Just
881f30337SRick Edgecombe  * stick to the basics and hope the compiler doesn't do anything strange.
981f30337SRick Edgecombe  */
1081f30337SRick Edgecombe 
1181f30337SRick Edgecombe #define _GNU_SOURCE
1281f30337SRick Edgecombe 
1381f30337SRick Edgecombe #include <sys/syscall.h>
1481f30337SRick Edgecombe #include <asm/mman.h>
1581f30337SRick Edgecombe #include <sys/mman.h>
1681f30337SRick Edgecombe #include <sys/stat.h>
1781f30337SRick Edgecombe #include <sys/wait.h>
1881f30337SRick Edgecombe #include <stdio.h>
1981f30337SRick Edgecombe #include <stdlib.h>
2081f30337SRick Edgecombe #include <fcntl.h>
2181f30337SRick Edgecombe #include <unistd.h>
2281f30337SRick Edgecombe #include <string.h>
2381f30337SRick Edgecombe #include <errno.h>
2481f30337SRick Edgecombe #include <stdbool.h>
2581f30337SRick Edgecombe #include <x86intrin.h>
2681f30337SRick Edgecombe #include <asm/prctl.h>
2781f30337SRick Edgecombe #include <sys/prctl.h>
2881f30337SRick Edgecombe #include <stdint.h>
2981f30337SRick Edgecombe #include <signal.h>
3081f30337SRick Edgecombe #include <pthread.h>
3181f30337SRick Edgecombe #include <sys/ioctl.h>
3281f30337SRick Edgecombe #include <linux/userfaultfd.h>
3381f30337SRick Edgecombe #include <setjmp.h>
3481f30337SRick Edgecombe #include <sys/ptrace.h>
3581f30337SRick Edgecombe #include <sys/signal.h>
3681f30337SRick Edgecombe #include <linux/elf.h>
37*29edd8b0SJiri Olsa #include <linux/perf_event.h>
3881f30337SRick Edgecombe 
3981f30337SRick Edgecombe /*
4081f30337SRick Edgecombe  * Define the ABI defines if needed, so people can run the tests
4181f30337SRick Edgecombe  * without building the headers.
4281f30337SRick Edgecombe  */
4381f30337SRick Edgecombe #ifndef __NR_map_shadow_stack
446ea7bb00SRick Edgecombe #define __NR_map_shadow_stack	453
4581f30337SRick Edgecombe 
4681f30337SRick Edgecombe #define SHADOW_STACK_SET_TOKEN	(1ULL << 0)
4781f30337SRick Edgecombe 
4881f30337SRick Edgecombe #define ARCH_SHSTK_ENABLE	0x5001
4981f30337SRick Edgecombe #define ARCH_SHSTK_DISABLE	0x5002
5081f30337SRick Edgecombe #define ARCH_SHSTK_LOCK		0x5003
5181f30337SRick Edgecombe #define ARCH_SHSTK_UNLOCK	0x5004
5281f30337SRick Edgecombe #define ARCH_SHSTK_STATUS	0x5005
5381f30337SRick Edgecombe 
5481f30337SRick Edgecombe #define ARCH_SHSTK_SHSTK	(1ULL <<  0)
5581f30337SRick Edgecombe #define ARCH_SHSTK_WRSS		(1ULL <<  1)
5681f30337SRick Edgecombe 
5781f30337SRick Edgecombe #define NT_X86_SHSTK	0x204
5881f30337SRick Edgecombe #endif
5981f30337SRick Edgecombe 
6081f30337SRick Edgecombe #define SS_SIZE 0x200000
6181f30337SRick Edgecombe #define PAGE_SIZE 0x1000
6281f30337SRick Edgecombe 
6381f30337SRick Edgecombe #if (__GNUC__ < 8) || (__GNUC__ == 8 && __GNUC_MINOR__ < 5)
main(int argc,char * argv[])6481f30337SRick Edgecombe int main(int argc, char *argv[])
6581f30337SRick Edgecombe {
6681f30337SRick Edgecombe 	printf("[SKIP]\tCompiler does not support CET.\n");
6781f30337SRick Edgecombe 	return 0;
6881f30337SRick Edgecombe }
6981f30337SRick Edgecombe #else
write_shstk(unsigned long * addr,unsigned long val)7081f30337SRick Edgecombe void write_shstk(unsigned long *addr, unsigned long val)
7181f30337SRick Edgecombe {
7281f30337SRick Edgecombe 	asm volatile("wrssq %[val], (%[addr])\n"
7381f30337SRick Edgecombe 		     : "=m" (addr)
7481f30337SRick Edgecombe 		     : [addr] "r" (addr), [val] "r" (val));
7581f30337SRick Edgecombe }
7681f30337SRick Edgecombe 
get_ssp(void)7781f30337SRick Edgecombe static inline unsigned long __attribute__((always_inline)) get_ssp(void)
7881f30337SRick Edgecombe {
7981f30337SRick Edgecombe 	unsigned long ret = 0;
8081f30337SRick Edgecombe 
8181f30337SRick Edgecombe 	asm volatile("xor %0, %0; rdsspq %0" : "=r" (ret));
8281f30337SRick Edgecombe 	return ret;
8381f30337SRick Edgecombe }
8481f30337SRick Edgecombe 
8581f30337SRick Edgecombe /*
8681f30337SRick Edgecombe  * For use in inline enablement of shadow stack.
8781f30337SRick Edgecombe  *
8881f30337SRick Edgecombe  * The program can't return from the point where shadow stack gets enabled
8981f30337SRick Edgecombe  * because there will be no address on the shadow stack. So it can't use
9081f30337SRick Edgecombe  * syscall() for enablement, since it is a function.
9181f30337SRick Edgecombe  *
9281f30337SRick Edgecombe  * Based on code from nolibc.h. Keep a copy here because this can't pull in all
9381f30337SRick Edgecombe  * of nolibc.h.
9481f30337SRick Edgecombe  */
9581f30337SRick Edgecombe #define ARCH_PRCTL(arg1, arg2)					\
9681f30337SRick Edgecombe ({								\
9781f30337SRick Edgecombe 	long _ret;						\
9881f30337SRick Edgecombe 	register long _num  asm("eax") = __NR_arch_prctl;	\
9981f30337SRick Edgecombe 	register long _arg1 asm("rdi") = (long)(arg1);		\
10081f30337SRick Edgecombe 	register long _arg2 asm("rsi") = (long)(arg2);		\
10181f30337SRick Edgecombe 								\
10281f30337SRick Edgecombe 	asm volatile (						\
10381f30337SRick Edgecombe 		"syscall\n"					\
10481f30337SRick Edgecombe 		: "=a"(_ret)					\
10581f30337SRick Edgecombe 		: "r"(_arg1), "r"(_arg2),			\
10681f30337SRick Edgecombe 		  "0"(_num)					\
10781f30337SRick Edgecombe 		: "rcx", "r11", "memory", "cc"			\
10881f30337SRick Edgecombe 	);							\
10981f30337SRick Edgecombe 	_ret;							\
11081f30337SRick Edgecombe })
11181f30337SRick Edgecombe 
create_shstk(void * addr)11281f30337SRick Edgecombe void *create_shstk(void *addr)
11381f30337SRick Edgecombe {
11481f30337SRick Edgecombe 	return (void *)syscall(__NR_map_shadow_stack, addr, SS_SIZE, SHADOW_STACK_SET_TOKEN);
11581f30337SRick Edgecombe }
11681f30337SRick Edgecombe 
create_normal_mem(void * addr)11781f30337SRick Edgecombe void *create_normal_mem(void *addr)
11881f30337SRick Edgecombe {
11981f30337SRick Edgecombe 	return mmap(addr, SS_SIZE, PROT_READ | PROT_WRITE,
12081f30337SRick Edgecombe 		    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
12181f30337SRick Edgecombe }
12281f30337SRick Edgecombe 
free_shstk(void * shstk)12381f30337SRick Edgecombe void free_shstk(void *shstk)
12481f30337SRick Edgecombe {
12581f30337SRick Edgecombe 	munmap(shstk, SS_SIZE);
12681f30337SRick Edgecombe }
12781f30337SRick Edgecombe 
reset_shstk(void * shstk)12881f30337SRick Edgecombe int reset_shstk(void *shstk)
12981f30337SRick Edgecombe {
13081f30337SRick Edgecombe 	return madvise(shstk, SS_SIZE, MADV_DONTNEED);
13181f30337SRick Edgecombe }
13281f30337SRick Edgecombe 
try_shstk(unsigned long new_ssp)13381f30337SRick Edgecombe void try_shstk(unsigned long new_ssp)
13481f30337SRick Edgecombe {
13581f30337SRick Edgecombe 	unsigned long ssp;
13681f30337SRick Edgecombe 
13781f30337SRick Edgecombe 	printf("[INFO]\tnew_ssp = %lx, *new_ssp = %lx\n",
13881f30337SRick Edgecombe 	       new_ssp, *((unsigned long *)new_ssp));
13981f30337SRick Edgecombe 
14081f30337SRick Edgecombe 	ssp = get_ssp();
14181f30337SRick Edgecombe 	printf("[INFO]\tchanging ssp from %lx to %lx\n", ssp, new_ssp);
14281f30337SRick Edgecombe 
14381f30337SRick Edgecombe 	asm volatile("rstorssp (%0)\n":: "r" (new_ssp));
14481f30337SRick Edgecombe 	asm volatile("saveprevssp");
14581f30337SRick Edgecombe 	printf("[INFO]\tssp is now %lx\n", get_ssp());
14681f30337SRick Edgecombe 
14781f30337SRick Edgecombe 	/* Switch back to original shadow stack */
14881f30337SRick Edgecombe 	ssp -= 8;
14981f30337SRick Edgecombe 	asm volatile("rstorssp (%0)\n":: "r" (ssp));
15081f30337SRick Edgecombe 	asm volatile("saveprevssp");
15181f30337SRick Edgecombe }
15281f30337SRick Edgecombe 
test_shstk_pivot(void)15381f30337SRick Edgecombe int test_shstk_pivot(void)
15481f30337SRick Edgecombe {
15581f30337SRick Edgecombe 	void *shstk = create_shstk(0);
15681f30337SRick Edgecombe 
15781f30337SRick Edgecombe 	if (shstk == MAP_FAILED) {
15881f30337SRick Edgecombe 		printf("[FAIL]\tError creating shadow stack: %d\n", errno);
15981f30337SRick Edgecombe 		return 1;
16081f30337SRick Edgecombe 	}
16181f30337SRick Edgecombe 	try_shstk((unsigned long)shstk + SS_SIZE - 8);
16281f30337SRick Edgecombe 	free_shstk(shstk);
16381f30337SRick Edgecombe 
16481f30337SRick Edgecombe 	printf("[OK]\tShadow stack pivot\n");
16581f30337SRick Edgecombe 	return 0;
16681f30337SRick Edgecombe }
16781f30337SRick Edgecombe 
test_shstk_faults(void)16881f30337SRick Edgecombe int test_shstk_faults(void)
16981f30337SRick Edgecombe {
17081f30337SRick Edgecombe 	unsigned long *shstk = create_shstk(0);
17181f30337SRick Edgecombe 
17281f30337SRick Edgecombe 	/* Read shadow stack, test if it's zero to not get read optimized out */
17381f30337SRick Edgecombe 	if (*shstk != 0)
17481f30337SRick Edgecombe 		goto err;
17581f30337SRick Edgecombe 
17681f30337SRick Edgecombe 	/* Wrss memory that was already read. */
17781f30337SRick Edgecombe 	write_shstk(shstk, 1);
17881f30337SRick Edgecombe 	if (*shstk != 1)
17981f30337SRick Edgecombe 		goto err;
18081f30337SRick Edgecombe 
18181f30337SRick Edgecombe 	/* Page out memory, so we can wrss it again. */
18281f30337SRick Edgecombe 	if (reset_shstk((void *)shstk))
18381f30337SRick Edgecombe 		goto err;
18481f30337SRick Edgecombe 
18581f30337SRick Edgecombe 	write_shstk(shstk, 1);
18681f30337SRick Edgecombe 	if (*shstk != 1)
18781f30337SRick Edgecombe 		goto err;
18881f30337SRick Edgecombe 
18981f30337SRick Edgecombe 	printf("[OK]\tShadow stack faults\n");
19081f30337SRick Edgecombe 	return 0;
19181f30337SRick Edgecombe 
19281f30337SRick Edgecombe err:
19381f30337SRick Edgecombe 	return 1;
19481f30337SRick Edgecombe }
19581f30337SRick Edgecombe 
19681f30337SRick Edgecombe unsigned long saved_ssp;
19781f30337SRick Edgecombe unsigned long saved_ssp_val;
19881f30337SRick Edgecombe volatile bool segv_triggered;
19981f30337SRick Edgecombe 
violate_ss(void)20081f30337SRick Edgecombe void __attribute__((noinline)) violate_ss(void)
20181f30337SRick Edgecombe {
20281f30337SRick Edgecombe 	saved_ssp = get_ssp();
20381f30337SRick Edgecombe 	saved_ssp_val = *(unsigned long *)saved_ssp;
20481f30337SRick Edgecombe 
20581f30337SRick Edgecombe 	/* Corrupt shadow stack */
20681f30337SRick Edgecombe 	printf("[INFO]\tCorrupting shadow stack\n");
20781f30337SRick Edgecombe 	write_shstk((void *)saved_ssp, 0);
20881f30337SRick Edgecombe }
20981f30337SRick Edgecombe 
segv_handler(int signum,siginfo_t * si,void * uc)21081f30337SRick Edgecombe void segv_handler(int signum, siginfo_t *si, void *uc)
21181f30337SRick Edgecombe {
21281f30337SRick Edgecombe 	printf("[INFO]\tGenerated shadow stack violation successfully\n");
21381f30337SRick Edgecombe 
21481f30337SRick Edgecombe 	segv_triggered = true;
21581f30337SRick Edgecombe 
21681f30337SRick Edgecombe 	/* Fix shadow stack */
21781f30337SRick Edgecombe 	write_shstk((void *)saved_ssp, saved_ssp_val);
21881f30337SRick Edgecombe }
21981f30337SRick Edgecombe 
test_shstk_violation(void)22081f30337SRick Edgecombe int test_shstk_violation(void)
22181f30337SRick Edgecombe {
22281f30337SRick Edgecombe 	struct sigaction sa = {};
22381f30337SRick Edgecombe 
22481f30337SRick Edgecombe 	sa.sa_sigaction = segv_handler;
22581f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
22681f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
22781f30337SRick Edgecombe 		return 1;
22881f30337SRick Edgecombe 
22981f30337SRick Edgecombe 	segv_triggered = false;
23081f30337SRick Edgecombe 
23181f30337SRick Edgecombe 	/* Make sure segv_triggered is set before violate_ss() */
23281f30337SRick Edgecombe 	asm volatile("" : : : "memory");
23381f30337SRick Edgecombe 
23481f30337SRick Edgecombe 	violate_ss();
23581f30337SRick Edgecombe 
23681f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
23781f30337SRick Edgecombe 
23881f30337SRick Edgecombe 	printf("[OK]\tShadow stack violation test\n");
23981f30337SRick Edgecombe 
24081f30337SRick Edgecombe 	return !segv_triggered;
24181f30337SRick Edgecombe }
24281f30337SRick Edgecombe 
24381f30337SRick Edgecombe /* Gup test state */
24481f30337SRick Edgecombe #define MAGIC_VAL 0x12345678
24581f30337SRick Edgecombe bool is_shstk_access;
24681f30337SRick Edgecombe void *shstk_ptr;
24781f30337SRick Edgecombe int fd;
24881f30337SRick Edgecombe 
reset_test_shstk(void * addr)24981f30337SRick Edgecombe void reset_test_shstk(void *addr)
25081f30337SRick Edgecombe {
25181f30337SRick Edgecombe 	if (shstk_ptr)
25281f30337SRick Edgecombe 		free_shstk(shstk_ptr);
25381f30337SRick Edgecombe 	shstk_ptr = create_shstk(addr);
25481f30337SRick Edgecombe }
25581f30337SRick Edgecombe 
test_access_fix_handler(int signum,siginfo_t * si,void * uc)25681f30337SRick Edgecombe void test_access_fix_handler(int signum, siginfo_t *si, void *uc)
25781f30337SRick Edgecombe {
25881f30337SRick Edgecombe 	printf("[INFO]\tViolation from %s\n", is_shstk_access ? "shstk access" : "normal write");
25981f30337SRick Edgecombe 
26081f30337SRick Edgecombe 	segv_triggered = true;
26181f30337SRick Edgecombe 
26281f30337SRick Edgecombe 	/* Fix shadow stack */
26381f30337SRick Edgecombe 	if (is_shstk_access) {
26481f30337SRick Edgecombe 		reset_test_shstk(shstk_ptr);
26581f30337SRick Edgecombe 		return;
26681f30337SRick Edgecombe 	}
26781f30337SRick Edgecombe 
26881f30337SRick Edgecombe 	free_shstk(shstk_ptr);
26981f30337SRick Edgecombe 	create_normal_mem(shstk_ptr);
27081f30337SRick Edgecombe }
27181f30337SRick Edgecombe 
test_shstk_access(void * ptr)27281f30337SRick Edgecombe bool test_shstk_access(void *ptr)
27381f30337SRick Edgecombe {
27481f30337SRick Edgecombe 	is_shstk_access = true;
27581f30337SRick Edgecombe 	segv_triggered = false;
27681f30337SRick Edgecombe 	write_shstk(ptr, MAGIC_VAL);
27781f30337SRick Edgecombe 
27881f30337SRick Edgecombe 	asm volatile("" : : : "memory");
27981f30337SRick Edgecombe 
28081f30337SRick Edgecombe 	return segv_triggered;
28181f30337SRick Edgecombe }
28281f30337SRick Edgecombe 
test_write_access(void * ptr)28381f30337SRick Edgecombe bool test_write_access(void *ptr)
28481f30337SRick Edgecombe {
28581f30337SRick Edgecombe 	is_shstk_access = false;
28681f30337SRick Edgecombe 	segv_triggered = false;
28781f30337SRick Edgecombe 	*(unsigned long *)ptr = MAGIC_VAL;
28881f30337SRick Edgecombe 
28981f30337SRick Edgecombe 	asm volatile("" : : : "memory");
29081f30337SRick Edgecombe 
29181f30337SRick Edgecombe 	return segv_triggered;
29281f30337SRick Edgecombe }
29381f30337SRick Edgecombe 
gup_write(void * ptr)29481f30337SRick Edgecombe bool gup_write(void *ptr)
29581f30337SRick Edgecombe {
29681f30337SRick Edgecombe 	unsigned long val;
29781f30337SRick Edgecombe 
29881f30337SRick Edgecombe 	lseek(fd, (unsigned long)ptr, SEEK_SET);
29981f30337SRick Edgecombe 	if (write(fd, &val, sizeof(val)) < 0)
30081f30337SRick Edgecombe 		return 1;
30181f30337SRick Edgecombe 
30281f30337SRick Edgecombe 	return 0;
30381f30337SRick Edgecombe }
30481f30337SRick Edgecombe 
gup_read(void * ptr)30581f30337SRick Edgecombe bool gup_read(void *ptr)
30681f30337SRick Edgecombe {
30781f30337SRick Edgecombe 	unsigned long val;
30881f30337SRick Edgecombe 
30981f30337SRick Edgecombe 	lseek(fd, (unsigned long)ptr, SEEK_SET);
31081f30337SRick Edgecombe 	if (read(fd, &val, sizeof(val)) < 0)
31181f30337SRick Edgecombe 		return 1;
31281f30337SRick Edgecombe 
31381f30337SRick Edgecombe 	return 0;
31481f30337SRick Edgecombe }
31581f30337SRick Edgecombe 
test_gup(void)31681f30337SRick Edgecombe int test_gup(void)
31781f30337SRick Edgecombe {
31881f30337SRick Edgecombe 	struct sigaction sa = {};
31981f30337SRick Edgecombe 	int status;
32081f30337SRick Edgecombe 	pid_t pid;
32181f30337SRick Edgecombe 
32281f30337SRick Edgecombe 	sa.sa_sigaction = test_access_fix_handler;
32381f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
32481f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
32581f30337SRick Edgecombe 		return 1;
32681f30337SRick Edgecombe 
32781f30337SRick Edgecombe 	segv_triggered = false;
32881f30337SRick Edgecombe 
32981f30337SRick Edgecombe 	fd = open("/proc/self/mem", O_RDWR);
33081f30337SRick Edgecombe 	if (fd == -1)
33181f30337SRick Edgecombe 		return 1;
33281f30337SRick Edgecombe 
33381f30337SRick Edgecombe 	reset_test_shstk(0);
33481f30337SRick Edgecombe 	if (gup_read(shstk_ptr))
33581f30337SRick Edgecombe 		return 1;
33681f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr))
33781f30337SRick Edgecombe 		return 1;
33881f30337SRick Edgecombe 	printf("[INFO]\tGup read -> shstk access success\n");
33981f30337SRick Edgecombe 
34081f30337SRick Edgecombe 	reset_test_shstk(0);
34181f30337SRick Edgecombe 	if (gup_write(shstk_ptr))
34281f30337SRick Edgecombe 		return 1;
34381f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr))
34481f30337SRick Edgecombe 		return 1;
34581f30337SRick Edgecombe 	printf("[INFO]\tGup write -> shstk access success\n");
34681f30337SRick Edgecombe 
34781f30337SRick Edgecombe 	reset_test_shstk(0);
34881f30337SRick Edgecombe 	if (gup_read(shstk_ptr))
34981f30337SRick Edgecombe 		return 1;
35081f30337SRick Edgecombe 	if (!test_write_access(shstk_ptr))
35181f30337SRick Edgecombe 		return 1;
35281f30337SRick Edgecombe 	printf("[INFO]\tGup read -> write access success\n");
35381f30337SRick Edgecombe 
35481f30337SRick Edgecombe 	reset_test_shstk(0);
35581f30337SRick Edgecombe 	if (gup_write(shstk_ptr))
35681f30337SRick Edgecombe 		return 1;
35781f30337SRick Edgecombe 	if (!test_write_access(shstk_ptr))
35881f30337SRick Edgecombe 		return 1;
35981f30337SRick Edgecombe 	printf("[INFO]\tGup write -> write access success\n");
36081f30337SRick Edgecombe 
36181f30337SRick Edgecombe 	close(fd);
36281f30337SRick Edgecombe 
36381f30337SRick Edgecombe 	/* COW/gup test */
36481f30337SRick Edgecombe 	reset_test_shstk(0);
36581f30337SRick Edgecombe 	pid = fork();
36681f30337SRick Edgecombe 	if (!pid) {
36781f30337SRick Edgecombe 		fd = open("/proc/self/mem", O_RDWR);
36881f30337SRick Edgecombe 		if (fd == -1)
36981f30337SRick Edgecombe 			exit(1);
37081f30337SRick Edgecombe 
37181f30337SRick Edgecombe 		if (gup_write(shstk_ptr)) {
37281f30337SRick Edgecombe 			close(fd);
37381f30337SRick Edgecombe 			exit(1);
37481f30337SRick Edgecombe 		}
37581f30337SRick Edgecombe 		close(fd);
37681f30337SRick Edgecombe 		exit(0);
37781f30337SRick Edgecombe 	}
37881f30337SRick Edgecombe 	waitpid(pid, &status, 0);
37981f30337SRick Edgecombe 	if (WEXITSTATUS(status)) {
38081f30337SRick Edgecombe 		printf("[FAIL]\tWrite in child failed\n");
38181f30337SRick Edgecombe 		return 1;
38281f30337SRick Edgecombe 	}
38381f30337SRick Edgecombe 	if (*(unsigned long *)shstk_ptr == MAGIC_VAL) {
38481f30337SRick Edgecombe 		printf("[FAIL]\tWrite in child wrote through to shared memory\n");
38581f30337SRick Edgecombe 		return 1;
38681f30337SRick Edgecombe 	}
38781f30337SRick Edgecombe 
38881f30337SRick Edgecombe 	printf("[INFO]\tCow gup write -> write access success\n");
38981f30337SRick Edgecombe 
39081f30337SRick Edgecombe 	free_shstk(shstk_ptr);
39181f30337SRick Edgecombe 
39281f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
39381f30337SRick Edgecombe 
39481f30337SRick Edgecombe 	printf("[OK]\tShadow gup test\n");
39581f30337SRick Edgecombe 
39681f30337SRick Edgecombe 	return 0;
39781f30337SRick Edgecombe }
39881f30337SRick Edgecombe 
test_mprotect(void)39981f30337SRick Edgecombe int test_mprotect(void)
40081f30337SRick Edgecombe {
40181f30337SRick Edgecombe 	struct sigaction sa = {};
40281f30337SRick Edgecombe 
40381f30337SRick Edgecombe 	sa.sa_sigaction = test_access_fix_handler;
40481f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
40581f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
40681f30337SRick Edgecombe 		return 1;
40781f30337SRick Edgecombe 
40881f30337SRick Edgecombe 	segv_triggered = false;
40981f30337SRick Edgecombe 
41081f30337SRick Edgecombe 	/* mprotect a shadow stack as read only */
41181f30337SRick Edgecombe 	reset_test_shstk(0);
41281f30337SRick Edgecombe 	if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {
41381f30337SRick Edgecombe 		printf("[FAIL]\tmprotect(PROT_READ) failed\n");
41481f30337SRick Edgecombe 		return 1;
41581f30337SRick Edgecombe 	}
41681f30337SRick Edgecombe 
41781f30337SRick Edgecombe 	/* try to wrss it and fail */
41881f30337SRick Edgecombe 	if (!test_shstk_access(shstk_ptr)) {
41981f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack access to read-only memory succeeded\n");
42081f30337SRick Edgecombe 		return 1;
42181f30337SRick Edgecombe 	}
42281f30337SRick Edgecombe 
42381f30337SRick Edgecombe 	/*
42481f30337SRick Edgecombe 	 * The shadow stack was reset above to resolve the fault, make the new one
42581f30337SRick Edgecombe 	 * read-only.
42681f30337SRick Edgecombe 	 */
42781f30337SRick Edgecombe 	if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {
42881f30337SRick Edgecombe 		printf("[FAIL]\tmprotect(PROT_READ) failed\n");
42981f30337SRick Edgecombe 		return 1;
43081f30337SRick Edgecombe 	}
43181f30337SRick Edgecombe 
43281f30337SRick Edgecombe 	/* then back to writable */
43381f30337SRick Edgecombe 	if (mprotect(shstk_ptr, SS_SIZE, PROT_WRITE | PROT_READ) < 0) {
43481f30337SRick Edgecombe 		printf("[FAIL]\tmprotect(PROT_WRITE) failed\n");
43581f30337SRick Edgecombe 		return 1;
43681f30337SRick Edgecombe 	}
43781f30337SRick Edgecombe 
43881f30337SRick Edgecombe 	/* then wrss to it and succeed */
43981f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr)) {
44081f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack access to mprotect() writable memory failed\n");
44181f30337SRick Edgecombe 		return 1;
44281f30337SRick Edgecombe 	}
44381f30337SRick Edgecombe 
44481f30337SRick Edgecombe 	free_shstk(shstk_ptr);
44581f30337SRick Edgecombe 
44681f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
44781f30337SRick Edgecombe 
44881f30337SRick Edgecombe 	printf("[OK]\tmprotect() test\n");
44981f30337SRick Edgecombe 
45081f30337SRick Edgecombe 	return 0;
45181f30337SRick Edgecombe }
45281f30337SRick Edgecombe 
45381f30337SRick Edgecombe char zero[4096];
45481f30337SRick Edgecombe 
uffd_thread(void * arg)45581f30337SRick Edgecombe static void *uffd_thread(void *arg)
45681f30337SRick Edgecombe {
45781f30337SRick Edgecombe 	struct uffdio_copy req;
45881f30337SRick Edgecombe 	int uffd = *(int *)arg;
45981f30337SRick Edgecombe 	struct uffd_msg msg;
46081f30337SRick Edgecombe 	int ret;
46181f30337SRick Edgecombe 
46281f30337SRick Edgecombe 	while (1) {
46381f30337SRick Edgecombe 		ret = read(uffd, &msg, sizeof(msg));
46481f30337SRick Edgecombe 		if (ret > 0)
46581f30337SRick Edgecombe 			break;
46681f30337SRick Edgecombe 		else if (errno == EAGAIN)
46781f30337SRick Edgecombe 			continue;
46881f30337SRick Edgecombe 		return (void *)1;
46981f30337SRick Edgecombe 	}
47081f30337SRick Edgecombe 
47181f30337SRick Edgecombe 	req.dst = msg.arg.pagefault.address;
47281f30337SRick Edgecombe 	req.src = (__u64)zero;
47381f30337SRick Edgecombe 	req.len = 4096;
47481f30337SRick Edgecombe 	req.mode = 0;
47581f30337SRick Edgecombe 
47681f30337SRick Edgecombe 	if (ioctl(uffd, UFFDIO_COPY, &req))
47781f30337SRick Edgecombe 		return (void *)1;
47881f30337SRick Edgecombe 
47981f30337SRick Edgecombe 	return (void *)0;
48081f30337SRick Edgecombe }
48181f30337SRick Edgecombe 
test_userfaultfd(void)48281f30337SRick Edgecombe int test_userfaultfd(void)
48381f30337SRick Edgecombe {
48481f30337SRick Edgecombe 	struct uffdio_register uffdio_register;
48581f30337SRick Edgecombe 	struct uffdio_api uffdio_api;
48681f30337SRick Edgecombe 	struct sigaction sa = {};
48781f30337SRick Edgecombe 	pthread_t thread;
48881f30337SRick Edgecombe 	void *res;
48981f30337SRick Edgecombe 	int uffd;
49081f30337SRick Edgecombe 
49181f30337SRick Edgecombe 	sa.sa_sigaction = test_access_fix_handler;
49281f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
49381f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
49481f30337SRick Edgecombe 		return 1;
49581f30337SRick Edgecombe 
49681f30337SRick Edgecombe 	uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
49781f30337SRick Edgecombe 	if (uffd < 0) {
49881f30337SRick Edgecombe 		printf("[SKIP]\tUserfaultfd unavailable.\n");
49981f30337SRick Edgecombe 		return 0;
50081f30337SRick Edgecombe 	}
50181f30337SRick Edgecombe 
50281f30337SRick Edgecombe 	reset_test_shstk(0);
50381f30337SRick Edgecombe 
50481f30337SRick Edgecombe 	uffdio_api.api = UFFD_API;
50581f30337SRick Edgecombe 	uffdio_api.features = 0;
50681f30337SRick Edgecombe 	if (ioctl(uffd, UFFDIO_API, &uffdio_api))
50781f30337SRick Edgecombe 		goto err;
50881f30337SRick Edgecombe 
50981f30337SRick Edgecombe 	uffdio_register.range.start = (__u64)shstk_ptr;
51081f30337SRick Edgecombe 	uffdio_register.range.len = 4096;
51181f30337SRick Edgecombe 	uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
51281f30337SRick Edgecombe 	if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
51381f30337SRick Edgecombe 		goto err;
51481f30337SRick Edgecombe 
51581f30337SRick Edgecombe 	if (pthread_create(&thread, NULL, &uffd_thread, &uffd))
51681f30337SRick Edgecombe 		goto err;
51781f30337SRick Edgecombe 
51881f30337SRick Edgecombe 	reset_shstk(shstk_ptr);
51981f30337SRick Edgecombe 	test_shstk_access(shstk_ptr);
52081f30337SRick Edgecombe 
52181f30337SRick Edgecombe 	if (pthread_join(thread, &res))
52281f30337SRick Edgecombe 		goto err;
52381f30337SRick Edgecombe 
52481f30337SRick Edgecombe 	if (test_shstk_access(shstk_ptr))
52581f30337SRick Edgecombe 		goto err;
52681f30337SRick Edgecombe 
52781f30337SRick Edgecombe 	free_shstk(shstk_ptr);
52881f30337SRick Edgecombe 
52981f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
53081f30337SRick Edgecombe 
53181f30337SRick Edgecombe 	if (!res)
53281f30337SRick Edgecombe 		printf("[OK]\tUserfaultfd test\n");
53381f30337SRick Edgecombe 	return !!res;
53481f30337SRick Edgecombe err:
53581f30337SRick Edgecombe 	free_shstk(shstk_ptr);
53681f30337SRick Edgecombe 	close(uffd);
53781f30337SRick Edgecombe 	signal(SIGSEGV, SIG_DFL);
53881f30337SRick Edgecombe 	return 1;
53981f30337SRick Edgecombe }
54081f30337SRick Edgecombe 
54181f30337SRick Edgecombe /* Simple linked list for keeping track of mappings in test_guard_gap() */
54281f30337SRick Edgecombe struct node {
54381f30337SRick Edgecombe 	struct node *next;
54481f30337SRick Edgecombe 	void *mapping;
54581f30337SRick Edgecombe };
54681f30337SRick Edgecombe 
54781f30337SRick Edgecombe /*
54881f30337SRick Edgecombe  * This tests whether mmap will place other mappings in a shadow stack's guard
54981f30337SRick Edgecombe  * gap. The steps are:
55081f30337SRick Edgecombe  *   1. Finds an empty place by mapping and unmapping something.
55181f30337SRick Edgecombe  *   2. Map a shadow stack in the middle of the known empty area.
55281f30337SRick Edgecombe  *   3. Map a bunch of PAGE_SIZE mappings. These will use the search down
55381f30337SRick Edgecombe  *      direction, filling any gaps until it encounters the shadow stack's
55481f30337SRick Edgecombe  *      guard gap.
55581f30337SRick Edgecombe  *   4. When a mapping lands below the shadow stack from step 2, then all
55681f30337SRick Edgecombe  *      of the above gaps are filled. The search down algorithm will have
55781f30337SRick Edgecombe  *      looked at the shadow stack gaps.
55881f30337SRick Edgecombe  *   5. See if it landed in the gap.
55981f30337SRick Edgecombe  */
test_guard_gap_other_gaps(void)560a9bc15cbSRick Edgecombe int test_guard_gap_other_gaps(void)
56181f30337SRick Edgecombe {
56281f30337SRick Edgecombe 	void *free_area, *shstk, *test_map = (void *)0xFFFFFFFFFFFFFFFF;
56381f30337SRick Edgecombe 	struct node *head = NULL, *cur;
56481f30337SRick Edgecombe 
56581f30337SRick Edgecombe 	free_area = mmap(0, SS_SIZE * 3, PROT_READ | PROT_WRITE,
56681f30337SRick Edgecombe 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
56781f30337SRick Edgecombe 	munmap(free_area, SS_SIZE * 3);
56881f30337SRick Edgecombe 
56981f30337SRick Edgecombe 	shstk = create_shstk(free_area + SS_SIZE);
57081f30337SRick Edgecombe 	if (shstk == MAP_FAILED)
57181f30337SRick Edgecombe 		return 1;
57281f30337SRick Edgecombe 
57381f30337SRick Edgecombe 	while (test_map > shstk) {
57481f30337SRick Edgecombe 		test_map = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE,
57581f30337SRick Edgecombe 				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
57681f30337SRick Edgecombe 		if (test_map == MAP_FAILED)
57781f30337SRick Edgecombe 			return 1;
57881f30337SRick Edgecombe 		cur = malloc(sizeof(*cur));
57981f30337SRick Edgecombe 		cur->mapping = test_map;
58081f30337SRick Edgecombe 
58181f30337SRick Edgecombe 		cur->next = head;
58281f30337SRick Edgecombe 		head = cur;
58381f30337SRick Edgecombe 	}
58481f30337SRick Edgecombe 
58581f30337SRick Edgecombe 	while (head) {
58681f30337SRick Edgecombe 		cur = head;
58781f30337SRick Edgecombe 		head = cur->next;
58881f30337SRick Edgecombe 		munmap(cur->mapping, PAGE_SIZE);
58981f30337SRick Edgecombe 		free(cur);
59081f30337SRick Edgecombe 	}
59181f30337SRick Edgecombe 
59281f30337SRick Edgecombe 	free_shstk(shstk);
59381f30337SRick Edgecombe 
59481f30337SRick Edgecombe 	if (shstk - test_map - PAGE_SIZE != PAGE_SIZE)
59581f30337SRick Edgecombe 		return 1;
59681f30337SRick Edgecombe 
597a9bc15cbSRick Edgecombe 	printf("[OK]\tGuard gap test, other mapping's gaps\n");
59881f30337SRick Edgecombe 
59981f30337SRick Edgecombe 	return 0;
60081f30337SRick Edgecombe }
60181f30337SRick Edgecombe 
602a9bc15cbSRick Edgecombe /* Tests respecting the guard gap of the mapping getting placed */
test_guard_gap_new_mappings_gaps(void)603a9bc15cbSRick Edgecombe int test_guard_gap_new_mappings_gaps(void)
604a9bc15cbSRick Edgecombe {
605a9bc15cbSRick Edgecombe 	void *free_area, *shstk_start, *test_map = (void *)0xFFFFFFFFFFFFFFFF;
606a9bc15cbSRick Edgecombe 	struct node *head = NULL, *cur;
607a9bc15cbSRick Edgecombe 	int ret = 0;
608a9bc15cbSRick Edgecombe 
609a9bc15cbSRick Edgecombe 	free_area = mmap(0, PAGE_SIZE * 4, PROT_READ | PROT_WRITE,
610a9bc15cbSRick Edgecombe 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
611a9bc15cbSRick Edgecombe 	munmap(free_area, PAGE_SIZE * 4);
612a9bc15cbSRick Edgecombe 
613a9bc15cbSRick Edgecombe 	/* Test letting map_shadow_stack find a free space */
614a9bc15cbSRick Edgecombe 	shstk_start = mmap(free_area, PAGE_SIZE, PROT_READ | PROT_WRITE,
615a9bc15cbSRick Edgecombe 			   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
616a9bc15cbSRick Edgecombe 	if (shstk_start == MAP_FAILED || shstk_start != free_area)
617a9bc15cbSRick Edgecombe 		return 1;
618a9bc15cbSRick Edgecombe 
619a9bc15cbSRick Edgecombe 	while (test_map > shstk_start) {
620a9bc15cbSRick Edgecombe 		test_map = (void *)syscall(__NR_map_shadow_stack, 0, PAGE_SIZE, 0);
621a9bc15cbSRick Edgecombe 		if (test_map == MAP_FAILED) {
622a9bc15cbSRick Edgecombe 			printf("[INFO]\tmap_shadow_stack MAP_FAILED\n");
623a9bc15cbSRick Edgecombe 			ret = 1;
624a9bc15cbSRick Edgecombe 			break;
625a9bc15cbSRick Edgecombe 		}
626a9bc15cbSRick Edgecombe 
627a9bc15cbSRick Edgecombe 		cur = malloc(sizeof(*cur));
628a9bc15cbSRick Edgecombe 		cur->mapping = test_map;
629a9bc15cbSRick Edgecombe 
630a9bc15cbSRick Edgecombe 		cur->next = head;
631a9bc15cbSRick Edgecombe 		head = cur;
632a9bc15cbSRick Edgecombe 
633a9bc15cbSRick Edgecombe 		if (test_map == free_area + PAGE_SIZE) {
634a9bc15cbSRick Edgecombe 			printf("[INFO]\tNew mapping has other mapping in guard gap!\n");
635a9bc15cbSRick Edgecombe 			ret = 1;
636a9bc15cbSRick Edgecombe 			break;
637a9bc15cbSRick Edgecombe 		}
638a9bc15cbSRick Edgecombe 	}
639a9bc15cbSRick Edgecombe 
640a9bc15cbSRick Edgecombe 	while (head) {
641a9bc15cbSRick Edgecombe 		cur = head;
642a9bc15cbSRick Edgecombe 		head = cur->next;
643a9bc15cbSRick Edgecombe 		munmap(cur->mapping, PAGE_SIZE);
644a9bc15cbSRick Edgecombe 		free(cur);
645a9bc15cbSRick Edgecombe 	}
646a9bc15cbSRick Edgecombe 
647a9bc15cbSRick Edgecombe 	munmap(shstk_start, PAGE_SIZE);
648a9bc15cbSRick Edgecombe 
649a9bc15cbSRick Edgecombe 	if (!ret)
650a9bc15cbSRick Edgecombe 		printf("[OK]\tGuard gap test, placement mapping's gaps\n");
651a9bc15cbSRick Edgecombe 
652a9bc15cbSRick Edgecombe 	return ret;
653a9bc15cbSRick Edgecombe }
654a9bc15cbSRick Edgecombe 
65581f30337SRick Edgecombe /*
65681f30337SRick Edgecombe  * Too complicated to pull it out of the 32 bit header, but also get the
65781f30337SRick Edgecombe  * 64 bit one needed above. Just define a copy here.
65881f30337SRick Edgecombe  */
65981f30337SRick Edgecombe #define __NR_compat_sigaction 67
66081f30337SRick Edgecombe 
66181f30337SRick Edgecombe /*
66281f30337SRick Edgecombe  * Call 32 bit signal handler to get 32 bit signals ABI. Make sure
66381f30337SRick Edgecombe  * to push the registers that will get clobbered.
66481f30337SRick Edgecombe  */
sigaction32(int signum,const struct sigaction * restrict act,struct sigaction * restrict oldact)66581f30337SRick Edgecombe int sigaction32(int signum, const struct sigaction *restrict act,
66681f30337SRick Edgecombe 		struct sigaction *restrict oldact)
66781f30337SRick Edgecombe {
66881f30337SRick Edgecombe 	register long syscall_reg asm("eax") = __NR_compat_sigaction;
66981f30337SRick Edgecombe 	register long signum_reg asm("ebx") = signum;
67081f30337SRick Edgecombe 	register long act_reg asm("ecx") = (long)act;
67181f30337SRick Edgecombe 	register long oldact_reg asm("edx") = (long)oldact;
67281f30337SRick Edgecombe 	int ret = 0;
67381f30337SRick Edgecombe 
67481f30337SRick Edgecombe 	asm volatile ("int $0x80;"
67581f30337SRick Edgecombe 		      : "=a"(ret), "=m"(oldact)
67681f30337SRick Edgecombe 		      : "r"(syscall_reg), "r"(signum_reg), "r"(act_reg),
67781f30337SRick Edgecombe 			"r"(oldact_reg)
67881f30337SRick Edgecombe 		      : "r8", "r9", "r10", "r11"
67981f30337SRick Edgecombe 		     );
68081f30337SRick Edgecombe 
68181f30337SRick Edgecombe 	return ret;
68281f30337SRick Edgecombe }
68381f30337SRick Edgecombe 
68481f30337SRick Edgecombe sigjmp_buf jmp_buffer;
68581f30337SRick Edgecombe 
segv_gp_handler(int signum,siginfo_t * si,void * uc)68681f30337SRick Edgecombe void segv_gp_handler(int signum, siginfo_t *si, void *uc)
68781f30337SRick Edgecombe {
68881f30337SRick Edgecombe 	segv_triggered = true;
68981f30337SRick Edgecombe 
69081f30337SRick Edgecombe 	/*
69181f30337SRick Edgecombe 	 * To work with old glibc, this can't rely on siglongjmp working with
69281f30337SRick Edgecombe 	 * shadow stack enabled, so disable shadow stack before siglongjmp().
69381f30337SRick Edgecombe 	 */
69481f30337SRick Edgecombe 	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
69581f30337SRick Edgecombe 	siglongjmp(jmp_buffer, -1);
69681f30337SRick Edgecombe }
69781f30337SRick Edgecombe 
69881f30337SRick Edgecombe /*
69981f30337SRick Edgecombe  * Transition to 32 bit mode and check that a #GP triggers a segfault.
70081f30337SRick Edgecombe  */
test_32bit(void)70181f30337SRick Edgecombe int test_32bit(void)
70281f30337SRick Edgecombe {
70381f30337SRick Edgecombe 	struct sigaction sa = {};
70481f30337SRick Edgecombe 	struct sigaction *sa32;
70581f30337SRick Edgecombe 
70681f30337SRick Edgecombe 	/* Create sigaction in 32 bit address range */
70781f30337SRick Edgecombe 	sa32 = mmap(0, 4096, PROT_READ | PROT_WRITE,
70881f30337SRick Edgecombe 		    MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
70981f30337SRick Edgecombe 	sa32->sa_flags = SA_SIGINFO;
71081f30337SRick Edgecombe 
71181f30337SRick Edgecombe 	sa.sa_sigaction = segv_gp_handler;
71281f30337SRick Edgecombe 	sa.sa_flags = SA_SIGINFO;
71381f30337SRick Edgecombe 	if (sigaction(SIGSEGV, &sa, NULL))
71481f30337SRick Edgecombe 		return 1;
71581f30337SRick Edgecombe 
71681f30337SRick Edgecombe 
71781f30337SRick Edgecombe 	segv_triggered = false;
71881f30337SRick Edgecombe 
71981f30337SRick Edgecombe 	/* Make sure segv_triggered is set before triggering the #GP */
72081f30337SRick Edgecombe 	asm volatile("" : : : "memory");
72181f30337SRick Edgecombe 
72281f30337SRick Edgecombe 	/*
72381f30337SRick Edgecombe 	 * Set handler to somewhere in 32 bit address space
72481f30337SRick Edgecombe 	 */
72581f30337SRick Edgecombe 	sa32->sa_handler = (void *)sa32;
72681f30337SRick Edgecombe 	if (sigaction32(SIGUSR1, sa32, NULL))
72781f30337SRick Edgecombe 		return 1;
72881f30337SRick Edgecombe 
72981f30337SRick Edgecombe 	if (!sigsetjmp(jmp_buffer, 1))
73081f30337SRick Edgecombe 		raise(SIGUSR1);
73181f30337SRick Edgecombe 
73281f30337SRick Edgecombe 	if (segv_triggered)
73381f30337SRick Edgecombe 		printf("[OK]\t32 bit test\n");
73481f30337SRick Edgecombe 
73581f30337SRick Edgecombe 	return !segv_triggered;
73681f30337SRick Edgecombe }
73781f30337SRick Edgecombe 
parse_uint_from_file(const char * file,const char * fmt)738*29edd8b0SJiri Olsa static int parse_uint_from_file(const char *file, const char *fmt)
739*29edd8b0SJiri Olsa {
740*29edd8b0SJiri Olsa 	int err, ret;
741*29edd8b0SJiri Olsa 	FILE *f;
742*29edd8b0SJiri Olsa 
743*29edd8b0SJiri Olsa 	f = fopen(file, "re");
744*29edd8b0SJiri Olsa 	if (!f) {
745*29edd8b0SJiri Olsa 		err = -errno;
746*29edd8b0SJiri Olsa 		printf("failed to open '%s': %d\n", file, err);
747*29edd8b0SJiri Olsa 		return err;
748*29edd8b0SJiri Olsa 	}
749*29edd8b0SJiri Olsa 	err = fscanf(f, fmt, &ret);
750*29edd8b0SJiri Olsa 	if (err != 1) {
751*29edd8b0SJiri Olsa 		err = err == EOF ? -EIO : -errno;
752*29edd8b0SJiri Olsa 		printf("failed to parse '%s': %d\n", file, err);
753*29edd8b0SJiri Olsa 		fclose(f);
754*29edd8b0SJiri Olsa 		return err;
755*29edd8b0SJiri Olsa 	}
756*29edd8b0SJiri Olsa 	fclose(f);
757*29edd8b0SJiri Olsa 	return ret;
758*29edd8b0SJiri Olsa }
759*29edd8b0SJiri Olsa 
determine_uprobe_perf_type(void)760*29edd8b0SJiri Olsa static int determine_uprobe_perf_type(void)
761*29edd8b0SJiri Olsa {
762*29edd8b0SJiri Olsa 	const char *file = "/sys/bus/event_source/devices/uprobe/type";
763*29edd8b0SJiri Olsa 
764*29edd8b0SJiri Olsa 	return parse_uint_from_file(file, "%d\n");
765*29edd8b0SJiri Olsa }
766*29edd8b0SJiri Olsa 
determine_uprobe_retprobe_bit(void)767*29edd8b0SJiri Olsa static int determine_uprobe_retprobe_bit(void)
768*29edd8b0SJiri Olsa {
769*29edd8b0SJiri Olsa 	const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe";
770*29edd8b0SJiri Olsa 
771*29edd8b0SJiri Olsa 	return parse_uint_from_file(file, "config:%d\n");
772*29edd8b0SJiri Olsa }
773*29edd8b0SJiri Olsa 
get_uprobe_offset(const void * addr)774*29edd8b0SJiri Olsa static ssize_t get_uprobe_offset(const void *addr)
775*29edd8b0SJiri Olsa {
776*29edd8b0SJiri Olsa 	size_t start, end, base;
777*29edd8b0SJiri Olsa 	char buf[256];
778*29edd8b0SJiri Olsa 	bool found = false;
779*29edd8b0SJiri Olsa 	FILE *f;
780*29edd8b0SJiri Olsa 
781*29edd8b0SJiri Olsa 	f = fopen("/proc/self/maps", "r");
782*29edd8b0SJiri Olsa 	if (!f)
783*29edd8b0SJiri Olsa 		return -errno;
784*29edd8b0SJiri Olsa 
785*29edd8b0SJiri Olsa 	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
786*29edd8b0SJiri Olsa 		if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
787*29edd8b0SJiri Olsa 			found = true;
788*29edd8b0SJiri Olsa 			break;
789*29edd8b0SJiri Olsa 		}
790*29edd8b0SJiri Olsa 	}
791*29edd8b0SJiri Olsa 
792*29edd8b0SJiri Olsa 	fclose(f);
793*29edd8b0SJiri Olsa 
794*29edd8b0SJiri Olsa 	if (!found)
795*29edd8b0SJiri Olsa 		return -ESRCH;
796*29edd8b0SJiri Olsa 
797*29edd8b0SJiri Olsa 	return (uintptr_t)addr - start + base;
798*29edd8b0SJiri Olsa }
799*29edd8b0SJiri Olsa 
uretprobe_trigger(void)800*29edd8b0SJiri Olsa static __attribute__((noinline)) void uretprobe_trigger(void)
801*29edd8b0SJiri Olsa {
802*29edd8b0SJiri Olsa 	asm volatile ("");
803*29edd8b0SJiri Olsa }
804*29edd8b0SJiri Olsa 
805*29edd8b0SJiri Olsa /*
806*29edd8b0SJiri Olsa  * This test setups return uprobe, which is sensitive to shadow stack
807*29edd8b0SJiri Olsa  * (crashes without extra fix). After executing the uretprobe we fail
808*29edd8b0SJiri Olsa  * the test if we receive SIGSEGV, no crash means we're good.
809*29edd8b0SJiri Olsa  *
810*29edd8b0SJiri Olsa  * Helper functions above borrowed from bpf selftests.
811*29edd8b0SJiri Olsa  */
test_uretprobe(void)812*29edd8b0SJiri Olsa static int test_uretprobe(void)
813*29edd8b0SJiri Olsa {
814*29edd8b0SJiri Olsa 	const size_t attr_sz = sizeof(struct perf_event_attr);
815*29edd8b0SJiri Olsa 	const char *file = "/proc/self/exe";
816*29edd8b0SJiri Olsa 	int bit, fd = 0, type, err = 1;
817*29edd8b0SJiri Olsa 	struct perf_event_attr attr;
818*29edd8b0SJiri Olsa 	struct sigaction sa = {};
819*29edd8b0SJiri Olsa 	ssize_t offset;
820*29edd8b0SJiri Olsa 
821*29edd8b0SJiri Olsa 	type = determine_uprobe_perf_type();
822*29edd8b0SJiri Olsa 	if (type < 0) {
823*29edd8b0SJiri Olsa 		if (type == -ENOENT)
824*29edd8b0SJiri Olsa 			printf("[SKIP]\tUretprobe test, uprobes are not available\n");
825*29edd8b0SJiri Olsa 		return 0;
826*29edd8b0SJiri Olsa 	}
827*29edd8b0SJiri Olsa 
828*29edd8b0SJiri Olsa 	offset = get_uprobe_offset(uretprobe_trigger);
829*29edd8b0SJiri Olsa 	if (offset < 0)
830*29edd8b0SJiri Olsa 		return 1;
831*29edd8b0SJiri Olsa 
832*29edd8b0SJiri Olsa 	bit = determine_uprobe_retprobe_bit();
833*29edd8b0SJiri Olsa 	if (bit < 0)
834*29edd8b0SJiri Olsa 		return 1;
835*29edd8b0SJiri Olsa 
836*29edd8b0SJiri Olsa 	sa.sa_sigaction = segv_gp_handler;
837*29edd8b0SJiri Olsa 	sa.sa_flags = SA_SIGINFO;
838*29edd8b0SJiri Olsa 	if (sigaction(SIGSEGV, &sa, NULL))
839*29edd8b0SJiri Olsa 		return 1;
840*29edd8b0SJiri Olsa 
841*29edd8b0SJiri Olsa 	/* Setup return uprobe through perf event interface. */
842*29edd8b0SJiri Olsa 	memset(&attr, 0, attr_sz);
843*29edd8b0SJiri Olsa 	attr.size = attr_sz;
844*29edd8b0SJiri Olsa 	attr.type = type;
845*29edd8b0SJiri Olsa 	attr.config = 1 << bit;
846*29edd8b0SJiri Olsa 	attr.config1 = (__u64) (unsigned long) file;
847*29edd8b0SJiri Olsa 	attr.config2 = offset;
848*29edd8b0SJiri Olsa 
849*29edd8b0SJiri Olsa 	fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */,
850*29edd8b0SJiri Olsa 		     -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
851*29edd8b0SJiri Olsa 	if (fd < 0)
852*29edd8b0SJiri Olsa 		goto out;
853*29edd8b0SJiri Olsa 
854*29edd8b0SJiri Olsa 	if (sigsetjmp(jmp_buffer, 1))
855*29edd8b0SJiri Olsa 		goto out;
856*29edd8b0SJiri Olsa 
857*29edd8b0SJiri Olsa 	ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK);
858*29edd8b0SJiri Olsa 
859*29edd8b0SJiri Olsa 	/*
860*29edd8b0SJiri Olsa 	 * This either segfaults and goes through sigsetjmp above
861*29edd8b0SJiri Olsa 	 * or succeeds and we're good.
862*29edd8b0SJiri Olsa 	 */
863*29edd8b0SJiri Olsa 	uretprobe_trigger();
864*29edd8b0SJiri Olsa 
865*29edd8b0SJiri Olsa 	printf("[OK]\tUretprobe test\n");
866*29edd8b0SJiri Olsa 	err = 0;
867*29edd8b0SJiri Olsa 
868*29edd8b0SJiri Olsa out:
869*29edd8b0SJiri Olsa 	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
870*29edd8b0SJiri Olsa 	signal(SIGSEGV, SIG_DFL);
871*29edd8b0SJiri Olsa 	if (fd)
872*29edd8b0SJiri Olsa 		close(fd);
873*29edd8b0SJiri Olsa 	return err;
874*29edd8b0SJiri Olsa }
875*29edd8b0SJiri Olsa 
segv_handler_ptrace(int signum,siginfo_t * si,void * uc)87681f30337SRick Edgecombe void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)
87781f30337SRick Edgecombe {
87881f30337SRick Edgecombe 	/* The SSP adjustment caused a segfault. */
87981f30337SRick Edgecombe 	exit(0);
88081f30337SRick Edgecombe }
88181f30337SRick Edgecombe 
test_ptrace(void)88281f30337SRick Edgecombe int test_ptrace(void)
88381f30337SRick Edgecombe {
88481f30337SRick Edgecombe 	unsigned long saved_ssp, ssp = 0;
88581f30337SRick Edgecombe 	struct sigaction sa= {};
88681f30337SRick Edgecombe 	struct iovec iov;
88781f30337SRick Edgecombe 	int status;
88881f30337SRick Edgecombe 	int pid;
88981f30337SRick Edgecombe 
89081f30337SRick Edgecombe 	iov.iov_base = &ssp;
89181f30337SRick Edgecombe 	iov.iov_len = sizeof(ssp);
89281f30337SRick Edgecombe 
89381f30337SRick Edgecombe 	pid = fork();
89481f30337SRick Edgecombe 	if (!pid) {
89581f30337SRick Edgecombe 		ssp = get_ssp();
89681f30337SRick Edgecombe 
89781f30337SRick Edgecombe 		sa.sa_sigaction = segv_handler_ptrace;
89881f30337SRick Edgecombe 		sa.sa_flags = SA_SIGINFO;
89981f30337SRick Edgecombe 		if (sigaction(SIGSEGV, &sa, NULL))
90081f30337SRick Edgecombe 			return 1;
90181f30337SRick Edgecombe 
90281f30337SRick Edgecombe 		ptrace(PTRACE_TRACEME, NULL, NULL, NULL);
90381f30337SRick Edgecombe 		/*
90481f30337SRick Edgecombe 		 * The parent will tweak the SSP and return from this function
90581f30337SRick Edgecombe 		 * will #CP.
90681f30337SRick Edgecombe 		 */
90781f30337SRick Edgecombe 		raise(SIGTRAP);
90881f30337SRick Edgecombe 
90981f30337SRick Edgecombe 		exit(1);
91081f30337SRick Edgecombe 	}
91181f30337SRick Edgecombe 
91281f30337SRick Edgecombe 	while (waitpid(pid, &status, 0) != -1 && WSTOPSIG(status) != SIGTRAP);
91381f30337SRick Edgecombe 
91481f30337SRick Edgecombe 	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_SHSTK, &iov)) {
91581f30337SRick Edgecombe 		printf("[INFO]\tFailed to PTRACE_GETREGS\n");
91681f30337SRick Edgecombe 		goto out_kill;
91781f30337SRick Edgecombe 	}
91881f30337SRick Edgecombe 
91981f30337SRick Edgecombe 	if (!ssp) {
92081f30337SRick Edgecombe 		printf("[INFO]\tPtrace child SSP was 0\n");
92181f30337SRick Edgecombe 		goto out_kill;
92281f30337SRick Edgecombe 	}
92381f30337SRick Edgecombe 
92481f30337SRick Edgecombe 	saved_ssp = ssp;
92581f30337SRick Edgecombe 
92681f30337SRick Edgecombe 	iov.iov_len = 0;
92781f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
92881f30337SRick Edgecombe 		printf("[INFO]\tToo small size accepted via PTRACE_SETREGS\n");
92981f30337SRick Edgecombe 		goto out_kill;
93081f30337SRick Edgecombe 	}
93181f30337SRick Edgecombe 
93281f30337SRick Edgecombe 	iov.iov_len = sizeof(ssp) + 1;
93381f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
93481f30337SRick Edgecombe 		printf("[INFO]\tToo large size accepted via PTRACE_SETREGS\n");
93581f30337SRick Edgecombe 		goto out_kill;
93681f30337SRick Edgecombe 	}
93781f30337SRick Edgecombe 
93881f30337SRick Edgecombe 	ssp += 1;
93981f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
94081f30337SRick Edgecombe 		printf("[INFO]\tUnaligned SSP written via PTRACE_SETREGS\n");
94181f30337SRick Edgecombe 		goto out_kill;
94281f30337SRick Edgecombe 	}
94381f30337SRick Edgecombe 
94481f30337SRick Edgecombe 	ssp = 0xFFFFFFFFFFFF0000;
94581f30337SRick Edgecombe 	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
94681f30337SRick Edgecombe 		printf("[INFO]\tKernel range SSP written via PTRACE_SETREGS\n");
94781f30337SRick Edgecombe 		goto out_kill;
94881f30337SRick Edgecombe 	}
94981f30337SRick Edgecombe 
95081f30337SRick Edgecombe 	/*
95181f30337SRick Edgecombe 	 * Tweak the SSP so the child with #CP when it resumes and returns
95281f30337SRick Edgecombe 	 * from raise()
95381f30337SRick Edgecombe 	 */
95481f30337SRick Edgecombe 	ssp = saved_ssp + 8;
95581f30337SRick Edgecombe 	iov.iov_len = sizeof(ssp);
95681f30337SRick Edgecombe 	if (ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {
95781f30337SRick Edgecombe 		printf("[INFO]\tFailed to PTRACE_SETREGS\n");
95881f30337SRick Edgecombe 		goto out_kill;
95981f30337SRick Edgecombe 	}
96081f30337SRick Edgecombe 
96181f30337SRick Edgecombe 	if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
96281f30337SRick Edgecombe 		printf("[INFO]\tFailed to PTRACE_DETACH\n");
96381f30337SRick Edgecombe 		goto out_kill;
96481f30337SRick Edgecombe 	}
96581f30337SRick Edgecombe 
96681f30337SRick Edgecombe 	waitpid(pid, &status, 0);
96781f30337SRick Edgecombe 	if (WEXITSTATUS(status))
96881f30337SRick Edgecombe 		return 1;
96981f30337SRick Edgecombe 
97081f30337SRick Edgecombe 	printf("[OK]\tPtrace test\n");
97181f30337SRick Edgecombe 	return 0;
97281f30337SRick Edgecombe 
97381f30337SRick Edgecombe out_kill:
97481f30337SRick Edgecombe 	kill(pid, SIGKILL);
97581f30337SRick Edgecombe 	return 1;
97681f30337SRick Edgecombe }
97781f30337SRick Edgecombe 
main(int argc,char * argv[])97881f30337SRick Edgecombe int main(int argc, char *argv[])
97981f30337SRick Edgecombe {
98081f30337SRick Edgecombe 	int ret = 0;
98181f30337SRick Edgecombe 
98281f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {
98381f30337SRick Edgecombe 		printf("[SKIP]\tCould not enable Shadow stack\n");
98481f30337SRick Edgecombe 		return 1;
98581f30337SRick Edgecombe 	}
98681f30337SRick Edgecombe 
98781f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {
98881f30337SRick Edgecombe 		ret = 1;
98981f30337SRick Edgecombe 		printf("[FAIL]\tDisabling shadow stack failed\n");
99081f30337SRick Edgecombe 	}
99181f30337SRick Edgecombe 
99281f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {
99381f30337SRick Edgecombe 		printf("[SKIP]\tCould not re-enable Shadow stack\n");
99481f30337SRick Edgecombe 		return 1;
99581f30337SRick Edgecombe 	}
99681f30337SRick Edgecombe 
99781f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_WRSS)) {
99881f30337SRick Edgecombe 		printf("[SKIP]\tCould not enable WRSS\n");
99981f30337SRick Edgecombe 		ret = 1;
100081f30337SRick Edgecombe 		goto out;
100181f30337SRick Edgecombe 	}
100281f30337SRick Edgecombe 
100381f30337SRick Edgecombe 	/* Should have succeeded if here, but this is a test, so double check. */
100481f30337SRick Edgecombe 	if (!get_ssp()) {
100581f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack disabled\n");
100681f30337SRick Edgecombe 		return 1;
100781f30337SRick Edgecombe 	}
100881f30337SRick Edgecombe 
100981f30337SRick Edgecombe 	if (test_shstk_pivot()) {
101081f30337SRick Edgecombe 		ret = 1;
101181f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack pivot\n");
101281f30337SRick Edgecombe 		goto out;
101381f30337SRick Edgecombe 	}
101481f30337SRick Edgecombe 
101581f30337SRick Edgecombe 	if (test_shstk_faults()) {
101681f30337SRick Edgecombe 		ret = 1;
101781f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack fault test\n");
101881f30337SRick Edgecombe 		goto out;
101981f30337SRick Edgecombe 	}
102081f30337SRick Edgecombe 
102181f30337SRick Edgecombe 	if (test_shstk_violation()) {
102281f30337SRick Edgecombe 		ret = 1;
102381f30337SRick Edgecombe 		printf("[FAIL]\tShadow stack violation test\n");
102481f30337SRick Edgecombe 		goto out;
102581f30337SRick Edgecombe 	}
102681f30337SRick Edgecombe 
102781f30337SRick Edgecombe 	if (test_gup()) {
102881f30337SRick Edgecombe 		ret = 1;
102981f30337SRick Edgecombe 		printf("[FAIL]\tShadow shadow stack gup\n");
103081f30337SRick Edgecombe 		goto out;
103181f30337SRick Edgecombe 	}
103281f30337SRick Edgecombe 
103381f30337SRick Edgecombe 	if (test_mprotect()) {
103481f30337SRick Edgecombe 		ret = 1;
103581f30337SRick Edgecombe 		printf("[FAIL]\tShadow shadow mprotect test\n");
103681f30337SRick Edgecombe 		goto out;
103781f30337SRick Edgecombe 	}
103881f30337SRick Edgecombe 
103981f30337SRick Edgecombe 	if (test_userfaultfd()) {
104081f30337SRick Edgecombe 		ret = 1;
104181f30337SRick Edgecombe 		printf("[FAIL]\tUserfaultfd test\n");
104281f30337SRick Edgecombe 		goto out;
104381f30337SRick Edgecombe 	}
104481f30337SRick Edgecombe 
1045a9bc15cbSRick Edgecombe 	if (test_guard_gap_other_gaps()) {
104681f30337SRick Edgecombe 		ret = 1;
1047a9bc15cbSRick Edgecombe 		printf("[FAIL]\tGuard gap test, other mappings' gaps\n");
1048a9bc15cbSRick Edgecombe 		goto out;
1049a9bc15cbSRick Edgecombe 	}
1050a9bc15cbSRick Edgecombe 
1051a9bc15cbSRick Edgecombe 	if (test_guard_gap_new_mappings_gaps()) {
1052a9bc15cbSRick Edgecombe 		ret = 1;
1053a9bc15cbSRick Edgecombe 		printf("[FAIL]\tGuard gap test, placement mapping's gaps\n");
105481f30337SRick Edgecombe 		goto out;
105581f30337SRick Edgecombe 	}
105681f30337SRick Edgecombe 
105781f30337SRick Edgecombe 	if (test_ptrace()) {
105881f30337SRick Edgecombe 		ret = 1;
105981f30337SRick Edgecombe 		printf("[FAIL]\tptrace test\n");
106081f30337SRick Edgecombe 	}
106181f30337SRick Edgecombe 
106281f30337SRick Edgecombe 	if (test_32bit()) {
106381f30337SRick Edgecombe 		ret = 1;
106481f30337SRick Edgecombe 		printf("[FAIL]\t32 bit test\n");
106581f30337SRick Edgecombe 		goto out;
106681f30337SRick Edgecombe 	}
106781f30337SRick Edgecombe 
1068*29edd8b0SJiri Olsa 	if (test_uretprobe()) {
1069*29edd8b0SJiri Olsa 		ret = 1;
1070*29edd8b0SJiri Olsa 		printf("[FAIL]\turetprobe test\n");
1071*29edd8b0SJiri Olsa 		goto out;
1072*29edd8b0SJiri Olsa 	}
1073*29edd8b0SJiri Olsa 
107481f30337SRick Edgecombe 	return ret;
107581f30337SRick Edgecombe 
107681f30337SRick Edgecombe out:
107781f30337SRick Edgecombe 	/*
107881f30337SRick Edgecombe 	 * Disable shadow stack before the function returns, or there will be a
107981f30337SRick Edgecombe 	 * shadow stack violation.
108081f30337SRick Edgecombe 	 */
108181f30337SRick Edgecombe 	if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {
108281f30337SRick Edgecombe 		ret = 1;
108381f30337SRick Edgecombe 		printf("[FAIL]\tDisabling shadow stack failed\n");
108481f30337SRick Edgecombe 	}
108581f30337SRick Edgecombe 
108681f30337SRick Edgecombe 	return ret;
108781f30337SRick Edgecombe }
108881f30337SRick Edgecombe #endif
1089