brintos

brintos / linux-shallow public Read only

0
0
Text · 22.8 KiB · 21af54d Raw
1089 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * This program test's basic kernel shadow stack support. It enables shadow4 * stack manual via the arch_prctl(), instead of relying on glibc. It's5 * Makefile doesn't compile with shadow stack support, so it doesn't rely on6 * any particular glibc. As a result it can't do any operations that require7 * special glibc shadow stack support (longjmp(), swapcontext(), etc). Just8 * stick to the basics and hope the compiler doesn't do anything strange.9 */10 11#define _GNU_SOURCE12 13#include <sys/syscall.h>14#include <asm/mman.h>15#include <sys/mman.h>16#include <sys/stat.h>17#include <sys/wait.h>18#include <stdio.h>19#include <stdlib.h>20#include <fcntl.h>21#include <unistd.h>22#include <string.h>23#include <errno.h>24#include <stdbool.h>25#include <x86intrin.h>26#include <asm/prctl.h>27#include <sys/prctl.h>28#include <stdint.h>29#include <signal.h>30#include <pthread.h>31#include <sys/ioctl.h>32#include <linux/userfaultfd.h>33#include <setjmp.h>34#include <sys/ptrace.h>35#include <sys/signal.h>36#include <linux/elf.h>37#include <linux/perf_event.h>38 39/*40 * Define the ABI defines if needed, so people can run the tests41 * without building the headers.42 */43#ifndef __NR_map_shadow_stack44#define __NR_map_shadow_stack	45345 46#define SHADOW_STACK_SET_TOKEN	(1ULL << 0)47 48#define ARCH_SHSTK_ENABLE	0x500149#define ARCH_SHSTK_DISABLE	0x500250#define ARCH_SHSTK_LOCK		0x500351#define ARCH_SHSTK_UNLOCK	0x500452#define ARCH_SHSTK_STATUS	0x500553 54#define ARCH_SHSTK_SHSTK	(1ULL <<  0)55#define ARCH_SHSTK_WRSS		(1ULL <<  1)56 57#define NT_X86_SHSTK	0x20458#endif59 60#define SS_SIZE 0x20000061#define PAGE_SIZE 0x100062 63#if (__GNUC__ < 8) || (__GNUC__ == 8 && __GNUC_MINOR__ < 5)64int main(int argc, char *argv[])65{66	printf("[SKIP]\tCompiler does not support CET.\n");67	return 0;68}69#else70void write_shstk(unsigned long *addr, unsigned long val)71{72	asm volatile("wrssq %[val], (%[addr])\n"73		     : "=m" (addr)74		     : [addr] "r" (addr), [val] "r" (val));75}76 77static inline unsigned long __attribute__((always_inline)) get_ssp(void)78{79	unsigned long ret = 0;80 81	asm volatile("xor %0, %0; rdsspq %0" : "=r" (ret));82	return ret;83}84 85/*86 * For use in inline enablement of shadow stack.87 *88 * The program can't return from the point where shadow stack gets enabled89 * because there will be no address on the shadow stack. So it can't use90 * syscall() for enablement, since it is a function.91 *92 * Based on code from nolibc.h. Keep a copy here because this can't pull in all93 * of nolibc.h.94 */95#define ARCH_PRCTL(arg1, arg2)					\96({								\97	long _ret;						\98	register long _num  asm("eax") = __NR_arch_prctl;	\99	register long _arg1 asm("rdi") = (long)(arg1);		\100	register long _arg2 asm("rsi") = (long)(arg2);		\101								\102	asm volatile (						\103		"syscall\n"					\104		: "=a"(_ret)					\105		: "r"(_arg1), "r"(_arg2),			\106		  "0"(_num)					\107		: "rcx", "r11", "memory", "cc"			\108	);							\109	_ret;							\110})111 112void *create_shstk(void *addr)113{114	return (void *)syscall(__NR_map_shadow_stack, addr, SS_SIZE, SHADOW_STACK_SET_TOKEN);115}116 117void *create_normal_mem(void *addr)118{119	return mmap(addr, SS_SIZE, PROT_READ | PROT_WRITE,120		    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);121}122 123void free_shstk(void *shstk)124{125	munmap(shstk, SS_SIZE);126}127 128int reset_shstk(void *shstk)129{130	return madvise(shstk, SS_SIZE, MADV_DONTNEED);131}132 133void try_shstk(unsigned long new_ssp)134{135	unsigned long ssp;136 137	printf("[INFO]\tnew_ssp = %lx, *new_ssp = %lx\n",138	       new_ssp, *((unsigned long *)new_ssp));139 140	ssp = get_ssp();141	printf("[INFO]\tchanging ssp from %lx to %lx\n", ssp, new_ssp);142 143	asm volatile("rstorssp (%0)\n":: "r" (new_ssp));144	asm volatile("saveprevssp");145	printf("[INFO]\tssp is now %lx\n", get_ssp());146 147	/* Switch back to original shadow stack */148	ssp -= 8;149	asm volatile("rstorssp (%0)\n":: "r" (ssp));150	asm volatile("saveprevssp");151}152 153int test_shstk_pivot(void)154{155	void *shstk = create_shstk(0);156 157	if (shstk == MAP_FAILED) {158		printf("[FAIL]\tError creating shadow stack: %d\n", errno);159		return 1;160	}161	try_shstk((unsigned long)shstk + SS_SIZE - 8);162	free_shstk(shstk);163 164	printf("[OK]\tShadow stack pivot\n");165	return 0;166}167 168int test_shstk_faults(void)169{170	unsigned long *shstk = create_shstk(0);171 172	/* Read shadow stack, test if it's zero to not get read optimized out */173	if (*shstk != 0)174		goto err;175 176	/* Wrss memory that was already read. */177	write_shstk(shstk, 1);178	if (*shstk != 1)179		goto err;180 181	/* Page out memory, so we can wrss it again. */182	if (reset_shstk((void *)shstk))183		goto err;184 185	write_shstk(shstk, 1);186	if (*shstk != 1)187		goto err;188 189	printf("[OK]\tShadow stack faults\n");190	return 0;191 192err:193	return 1;194}195 196unsigned long saved_ssp;197unsigned long saved_ssp_val;198volatile bool segv_triggered;199 200void __attribute__((noinline)) violate_ss(void)201{202	saved_ssp = get_ssp();203	saved_ssp_val = *(unsigned long *)saved_ssp;204 205	/* Corrupt shadow stack */206	printf("[INFO]\tCorrupting shadow stack\n");207	write_shstk((void *)saved_ssp, 0);208}209 210void segv_handler(int signum, siginfo_t *si, void *uc)211{212	printf("[INFO]\tGenerated shadow stack violation successfully\n");213 214	segv_triggered = true;215 216	/* Fix shadow stack */217	write_shstk((void *)saved_ssp, saved_ssp_val);218}219 220int test_shstk_violation(void)221{222	struct sigaction sa = {};223 224	sa.sa_sigaction = segv_handler;225	sa.sa_flags = SA_SIGINFO;226	if (sigaction(SIGSEGV, &sa, NULL))227		return 1;228 229	segv_triggered = false;230 231	/* Make sure segv_triggered is set before violate_ss() */232	asm volatile("" : : : "memory");233 234	violate_ss();235 236	signal(SIGSEGV, SIG_DFL);237 238	printf("[OK]\tShadow stack violation test\n");239 240	return !segv_triggered;241}242 243/* Gup test state */244#define MAGIC_VAL 0x12345678245bool is_shstk_access;246void *shstk_ptr;247int fd;248 249void reset_test_shstk(void *addr)250{251	if (shstk_ptr)252		free_shstk(shstk_ptr);253	shstk_ptr = create_shstk(addr);254}255 256void test_access_fix_handler(int signum, siginfo_t *si, void *uc)257{258	printf("[INFO]\tViolation from %s\n", is_shstk_access ? "shstk access" : "normal write");259 260	segv_triggered = true;261 262	/* Fix shadow stack */263	if (is_shstk_access) {264		reset_test_shstk(shstk_ptr);265		return;266	}267 268	free_shstk(shstk_ptr);269	create_normal_mem(shstk_ptr);270}271 272bool test_shstk_access(void *ptr)273{274	is_shstk_access = true;275	segv_triggered = false;276	write_shstk(ptr, MAGIC_VAL);277 278	asm volatile("" : : : "memory");279 280	return segv_triggered;281}282 283bool test_write_access(void *ptr)284{285	is_shstk_access = false;286	segv_triggered = false;287	*(unsigned long *)ptr = MAGIC_VAL;288 289	asm volatile("" : : : "memory");290 291	return segv_triggered;292}293 294bool gup_write(void *ptr)295{296	unsigned long val;297 298	lseek(fd, (unsigned long)ptr, SEEK_SET);299	if (write(fd, &val, sizeof(val)) < 0)300		return 1;301 302	return 0;303}304 305bool gup_read(void *ptr)306{307	unsigned long val;308 309	lseek(fd, (unsigned long)ptr, SEEK_SET);310	if (read(fd, &val, sizeof(val)) < 0)311		return 1;312 313	return 0;314}315 316int test_gup(void)317{318	struct sigaction sa = {};319	int status;320	pid_t pid;321 322	sa.sa_sigaction = test_access_fix_handler;323	sa.sa_flags = SA_SIGINFO;324	if (sigaction(SIGSEGV, &sa, NULL))325		return 1;326 327	segv_triggered = false;328 329	fd = open("/proc/self/mem", O_RDWR);330	if (fd == -1)331		return 1;332 333	reset_test_shstk(0);334	if (gup_read(shstk_ptr))335		return 1;336	if (test_shstk_access(shstk_ptr))337		return 1;338	printf("[INFO]\tGup read -> shstk access success\n");339 340	reset_test_shstk(0);341	if (gup_write(shstk_ptr))342		return 1;343	if (test_shstk_access(shstk_ptr))344		return 1;345	printf("[INFO]\tGup write -> shstk access success\n");346 347	reset_test_shstk(0);348	if (gup_read(shstk_ptr))349		return 1;350	if (!test_write_access(shstk_ptr))351		return 1;352	printf("[INFO]\tGup read -> write access success\n");353 354	reset_test_shstk(0);355	if (gup_write(shstk_ptr))356		return 1;357	if (!test_write_access(shstk_ptr))358		return 1;359	printf("[INFO]\tGup write -> write access success\n");360 361	close(fd);362 363	/* COW/gup test */364	reset_test_shstk(0);365	pid = fork();366	if (!pid) {367		fd = open("/proc/self/mem", O_RDWR);368		if (fd == -1)369			exit(1);370 371		if (gup_write(shstk_ptr)) {372			close(fd);373			exit(1);374		}375		close(fd);376		exit(0);377	}378	waitpid(pid, &status, 0);379	if (WEXITSTATUS(status)) {380		printf("[FAIL]\tWrite in child failed\n");381		return 1;382	}383	if (*(unsigned long *)shstk_ptr == MAGIC_VAL) {384		printf("[FAIL]\tWrite in child wrote through to shared memory\n");385		return 1;386	}387 388	printf("[INFO]\tCow gup write -> write access success\n");389 390	free_shstk(shstk_ptr);391 392	signal(SIGSEGV, SIG_DFL);393 394	printf("[OK]\tShadow gup test\n");395 396	return 0;397}398 399int test_mprotect(void)400{401	struct sigaction sa = {};402 403	sa.sa_sigaction = test_access_fix_handler;404	sa.sa_flags = SA_SIGINFO;405	if (sigaction(SIGSEGV, &sa, NULL))406		return 1;407 408	segv_triggered = false;409 410	/* mprotect a shadow stack as read only */411	reset_test_shstk(0);412	if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {413		printf("[FAIL]\tmprotect(PROT_READ) failed\n");414		return 1;415	}416 417	/* try to wrss it and fail */418	if (!test_shstk_access(shstk_ptr)) {419		printf("[FAIL]\tShadow stack access to read-only memory succeeded\n");420		return 1;421	}422 423	/*424	 * The shadow stack was reset above to resolve the fault, make the new one425	 * read-only.426	 */427	if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {428		printf("[FAIL]\tmprotect(PROT_READ) failed\n");429		return 1;430	}431 432	/* then back to writable */433	if (mprotect(shstk_ptr, SS_SIZE, PROT_WRITE | PROT_READ) < 0) {434		printf("[FAIL]\tmprotect(PROT_WRITE) failed\n");435		return 1;436	}437 438	/* then wrss to it and succeed */439	if (test_shstk_access(shstk_ptr)) {440		printf("[FAIL]\tShadow stack access to mprotect() writable memory failed\n");441		return 1;442	}443 444	free_shstk(shstk_ptr);445 446	signal(SIGSEGV, SIG_DFL);447 448	printf("[OK]\tmprotect() test\n");449 450	return 0;451}452 453char zero[4096];454 455static void *uffd_thread(void *arg)456{457	struct uffdio_copy req;458	int uffd = *(int *)arg;459	struct uffd_msg msg;460	int ret;461 462	while (1) {463		ret = read(uffd, &msg, sizeof(msg));464		if (ret > 0)465			break;466		else if (errno == EAGAIN)467			continue;468		return (void *)1;469	}470 471	req.dst = msg.arg.pagefault.address;472	req.src = (__u64)zero;473	req.len = 4096;474	req.mode = 0;475 476	if (ioctl(uffd, UFFDIO_COPY, &req))477		return (void *)1;478 479	return (void *)0;480}481 482int test_userfaultfd(void)483{484	struct uffdio_register uffdio_register;485	struct uffdio_api uffdio_api;486	struct sigaction sa = {};487	pthread_t thread;488	void *res;489	int uffd;490 491	sa.sa_sigaction = test_access_fix_handler;492	sa.sa_flags = SA_SIGINFO;493	if (sigaction(SIGSEGV, &sa, NULL))494		return 1;495 496	uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);497	if (uffd < 0) {498		printf("[SKIP]\tUserfaultfd unavailable.\n");499		return 0;500	}501 502	reset_test_shstk(0);503 504	uffdio_api.api = UFFD_API;505	uffdio_api.features = 0;506	if (ioctl(uffd, UFFDIO_API, &uffdio_api))507		goto err;508 509	uffdio_register.range.start = (__u64)shstk_ptr;510	uffdio_register.range.len = 4096;511	uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;512	if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))513		goto err;514 515	if (pthread_create(&thread, NULL, &uffd_thread, &uffd))516		goto err;517 518	reset_shstk(shstk_ptr);519	test_shstk_access(shstk_ptr);520 521	if (pthread_join(thread, &res))522		goto err;523 524	if (test_shstk_access(shstk_ptr))525		goto err;526 527	free_shstk(shstk_ptr);528 529	signal(SIGSEGV, SIG_DFL);530 531	if (!res)532		printf("[OK]\tUserfaultfd test\n");533	return !!res;534err:535	free_shstk(shstk_ptr);536	close(uffd);537	signal(SIGSEGV, SIG_DFL);538	return 1;539}540 541/* Simple linked list for keeping track of mappings in test_guard_gap() */542struct node {543	struct node *next;544	void *mapping;545};546 547/*548 * This tests whether mmap will place other mappings in a shadow stack's guard549 * gap. The steps are:550 *   1. Finds an empty place by mapping and unmapping something.551 *   2. Map a shadow stack in the middle of the known empty area.552 *   3. Map a bunch of PAGE_SIZE mappings. These will use the search down553 *      direction, filling any gaps until it encounters the shadow stack's554 *      guard gap.555 *   4. When a mapping lands below the shadow stack from step 2, then all556 *      of the above gaps are filled. The search down algorithm will have557 *      looked at the shadow stack gaps.558 *   5. See if it landed in the gap.559 */560int test_guard_gap_other_gaps(void)561{562	void *free_area, *shstk, *test_map = (void *)0xFFFFFFFFFFFFFFFF;563	struct node *head = NULL, *cur;564 565	free_area = mmap(0, SS_SIZE * 3, PROT_READ | PROT_WRITE,566			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);567	munmap(free_area, SS_SIZE * 3);568 569	shstk = create_shstk(free_area + SS_SIZE);570	if (shstk == MAP_FAILED)571		return 1;572 573	while (test_map > shstk) {574		test_map = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE,575				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);576		if (test_map == MAP_FAILED)577			return 1;578		cur = malloc(sizeof(*cur));579		cur->mapping = test_map;580 581		cur->next = head;582		head = cur;583	}584 585	while (head) {586		cur = head;587		head = cur->next;588		munmap(cur->mapping, PAGE_SIZE);589		free(cur);590	}591 592	free_shstk(shstk);593 594	if (shstk - test_map - PAGE_SIZE != PAGE_SIZE)595		return 1;596 597	printf("[OK]\tGuard gap test, other mapping's gaps\n");598 599	return 0;600}601 602/* Tests respecting the guard gap of the mapping getting placed */603int test_guard_gap_new_mappings_gaps(void)604{605	void *free_area, *shstk_start, *test_map = (void *)0xFFFFFFFFFFFFFFFF;606	struct node *head = NULL, *cur;607	int ret = 0;608 609	free_area = mmap(0, PAGE_SIZE * 4, PROT_READ | PROT_WRITE,610			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);611	munmap(free_area, PAGE_SIZE * 4);612 613	/* Test letting map_shadow_stack find a free space */614	shstk_start = mmap(free_area, PAGE_SIZE, PROT_READ | PROT_WRITE,615			   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);616	if (shstk_start == MAP_FAILED || shstk_start != free_area)617		return 1;618 619	while (test_map > shstk_start) {620		test_map = (void *)syscall(__NR_map_shadow_stack, 0, PAGE_SIZE, 0);621		if (test_map == MAP_FAILED) {622			printf("[INFO]\tmap_shadow_stack MAP_FAILED\n");623			ret = 1;624			break;625		}626 627		cur = malloc(sizeof(*cur));628		cur->mapping = test_map;629 630		cur->next = head;631		head = cur;632 633		if (test_map == free_area + PAGE_SIZE) {634			printf("[INFO]\tNew mapping has other mapping in guard gap!\n");635			ret = 1;636			break;637		}638	}639 640	while (head) {641		cur = head;642		head = cur->next;643		munmap(cur->mapping, PAGE_SIZE);644		free(cur);645	}646 647	munmap(shstk_start, PAGE_SIZE);648 649	if (!ret)650		printf("[OK]\tGuard gap test, placement mapping's gaps\n");651 652	return ret;653}654 655/*656 * Too complicated to pull it out of the 32 bit header, but also get the657 * 64 bit one needed above. Just define a copy here.658 */659#define __NR_compat_sigaction 67660 661/*662 * Call 32 bit signal handler to get 32 bit signals ABI. Make sure663 * to push the registers that will get clobbered.664 */665int sigaction32(int signum, const struct sigaction *restrict act,666		struct sigaction *restrict oldact)667{668	register long syscall_reg asm("eax") = __NR_compat_sigaction;669	register long signum_reg asm("ebx") = signum;670	register long act_reg asm("ecx") = (long)act;671	register long oldact_reg asm("edx") = (long)oldact;672	int ret = 0;673 674	asm volatile ("int $0x80;"675		      : "=a"(ret), "=m"(oldact)676		      : "r"(syscall_reg), "r"(signum_reg), "r"(act_reg),677			"r"(oldact_reg)678		      : "r8", "r9", "r10", "r11"679		     );680 681	return ret;682}683 684sigjmp_buf jmp_buffer;685 686void segv_gp_handler(int signum, siginfo_t *si, void *uc)687{688	segv_triggered = true;689 690	/*691	 * To work with old glibc, this can't rely on siglongjmp working with692	 * shadow stack enabled, so disable shadow stack before siglongjmp().693	 */694	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);695	siglongjmp(jmp_buffer, -1);696}697 698/*699 * Transition to 32 bit mode and check that a #GP triggers a segfault.700 */701int test_32bit(void)702{703	struct sigaction sa = {};704	struct sigaction *sa32;705 706	/* Create sigaction in 32 bit address range */707	sa32 = mmap(0, 4096, PROT_READ | PROT_WRITE,708		    MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);709	sa32->sa_flags = SA_SIGINFO;710 711	sa.sa_sigaction = segv_gp_handler;712	sa.sa_flags = SA_SIGINFO;713	if (sigaction(SIGSEGV, &sa, NULL))714		return 1;715 716 717	segv_triggered = false;718 719	/* Make sure segv_triggered is set before triggering the #GP */720	asm volatile("" : : : "memory");721 722	/*723	 * Set handler to somewhere in 32 bit address space724	 */725	sa32->sa_handler = (void *)sa32;726	if (sigaction32(SIGUSR1, sa32, NULL))727		return 1;728 729	if (!sigsetjmp(jmp_buffer, 1))730		raise(SIGUSR1);731 732	if (segv_triggered)733		printf("[OK]\t32 bit test\n");734 735	return !segv_triggered;736}737 738static int parse_uint_from_file(const char *file, const char *fmt)739{740	int err, ret;741	FILE *f;742 743	f = fopen(file, "re");744	if (!f) {745		err = -errno;746		printf("failed to open '%s': %d\n", file, err);747		return err;748	}749	err = fscanf(f, fmt, &ret);750	if (err != 1) {751		err = err == EOF ? -EIO : -errno;752		printf("failed to parse '%s': %d\n", file, err);753		fclose(f);754		return err;755	}756	fclose(f);757	return ret;758}759 760static int determine_uprobe_perf_type(void)761{762	const char *file = "/sys/bus/event_source/devices/uprobe/type";763 764	return parse_uint_from_file(file, "%d\n");765}766 767static int determine_uprobe_retprobe_bit(void)768{769	const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe";770 771	return parse_uint_from_file(file, "config:%d\n");772}773 774static ssize_t get_uprobe_offset(const void *addr)775{776	size_t start, end, base;777	char buf[256];778	bool found = false;779	FILE *f;780 781	f = fopen("/proc/self/maps", "r");782	if (!f)783		return -errno;784 785	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {786		if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {787			found = true;788			break;789		}790	}791 792	fclose(f);793 794	if (!found)795		return -ESRCH;796 797	return (uintptr_t)addr - start + base;798}799 800static __attribute__((noinline)) void uretprobe_trigger(void)801{802	asm volatile ("");803}804 805/*806 * This test setups return uprobe, which is sensitive to shadow stack807 * (crashes without extra fix). After executing the uretprobe we fail808 * the test if we receive SIGSEGV, no crash means we're good.809 *810 * Helper functions above borrowed from bpf selftests.811 */812static int test_uretprobe(void)813{814	const size_t attr_sz = sizeof(struct perf_event_attr);815	const char *file = "/proc/self/exe";816	int bit, fd = 0, type, err = 1;817	struct perf_event_attr attr;818	struct sigaction sa = {};819	ssize_t offset;820 821	type = determine_uprobe_perf_type();822	if (type < 0) {823		if (type == -ENOENT)824			printf("[SKIP]\tUretprobe test, uprobes are not available\n");825		return 0;826	}827 828	offset = get_uprobe_offset(uretprobe_trigger);829	if (offset < 0)830		return 1;831 832	bit = determine_uprobe_retprobe_bit();833	if (bit < 0)834		return 1;835 836	sa.sa_sigaction = segv_gp_handler;837	sa.sa_flags = SA_SIGINFO;838	if (sigaction(SIGSEGV, &sa, NULL))839		return 1;840 841	/* Setup return uprobe through perf event interface. */842	memset(&attr, 0, attr_sz);843	attr.size = attr_sz;844	attr.type = type;845	attr.config = 1 << bit;846	attr.config1 = (__u64) (unsigned long) file;847	attr.config2 = offset;848 849	fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */,850		     -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);851	if (fd < 0)852		goto out;853 854	if (sigsetjmp(jmp_buffer, 1))855		goto out;856 857	ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK);858 859	/*860	 * This either segfaults and goes through sigsetjmp above861	 * or succeeds and we're good.862	 */863	uretprobe_trigger();864 865	printf("[OK]\tUretprobe test\n");866	err = 0;867 868out:869	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);870	signal(SIGSEGV, SIG_DFL);871	if (fd)872		close(fd);873	return err;874}875 876void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)877{878	/* The SSP adjustment caused a segfault. */879	exit(0);880}881 882int test_ptrace(void)883{884	unsigned long saved_ssp, ssp = 0;885	struct sigaction sa= {};886	struct iovec iov;887	int status;888	int pid;889 890	iov.iov_base = &ssp;891	iov.iov_len = sizeof(ssp);892 893	pid = fork();894	if (!pid) {895		ssp = get_ssp();896 897		sa.sa_sigaction = segv_handler_ptrace;898		sa.sa_flags = SA_SIGINFO;899		if (sigaction(SIGSEGV, &sa, NULL))900			return 1;901 902		ptrace(PTRACE_TRACEME, NULL, NULL, NULL);903		/*904		 * The parent will tweak the SSP and return from this function905		 * will #CP.906		 */907		raise(SIGTRAP);908 909		exit(1);910	}911 912	while (waitpid(pid, &status, 0) != -1 && WSTOPSIG(status) != SIGTRAP);913 914	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_SHSTK, &iov)) {915		printf("[INFO]\tFailed to PTRACE_GETREGS\n");916		goto out_kill;917	}918 919	if (!ssp) {920		printf("[INFO]\tPtrace child SSP was 0\n");921		goto out_kill;922	}923 924	saved_ssp = ssp;925 926	iov.iov_len = 0;927	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {928		printf("[INFO]\tToo small size accepted via PTRACE_SETREGS\n");929		goto out_kill;930	}931 932	iov.iov_len = sizeof(ssp) + 1;933	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {934		printf("[INFO]\tToo large size accepted via PTRACE_SETREGS\n");935		goto out_kill;936	}937 938	ssp += 1;939	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {940		printf("[INFO]\tUnaligned SSP written via PTRACE_SETREGS\n");941		goto out_kill;942	}943 944	ssp = 0xFFFFFFFFFFFF0000;945	if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {946		printf("[INFO]\tKernel range SSP written via PTRACE_SETREGS\n");947		goto out_kill;948	}949 950	/*951	 * Tweak the SSP so the child with #CP when it resumes and returns952	 * from raise()953	 */954	ssp = saved_ssp + 8;955	iov.iov_len = sizeof(ssp);956	if (ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {957		printf("[INFO]\tFailed to PTRACE_SETREGS\n");958		goto out_kill;959	}960 961	if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {962		printf("[INFO]\tFailed to PTRACE_DETACH\n");963		goto out_kill;964	}965 966	waitpid(pid, &status, 0);967	if (WEXITSTATUS(status))968		return 1;969 970	printf("[OK]\tPtrace test\n");971	return 0;972 973out_kill:974	kill(pid, SIGKILL);975	return 1;976}977 978int main(int argc, char *argv[])979{980	int ret = 0;981 982	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {983		printf("[SKIP]\tCould not enable Shadow stack\n");984		return 1;985	}986 987	if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {988		ret = 1;989		printf("[FAIL]\tDisabling shadow stack failed\n");990	}991 992	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {993		printf("[SKIP]\tCould not re-enable Shadow stack\n");994		return 1;995	}996 997	if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_WRSS)) {998		printf("[SKIP]\tCould not enable WRSS\n");999		ret = 1;1000		goto out;1001	}1002 1003	/* Should have succeeded if here, but this is a test, so double check. */1004	if (!get_ssp()) {1005		printf("[FAIL]\tShadow stack disabled\n");1006		return 1;1007	}1008 1009	if (test_shstk_pivot()) {1010		ret = 1;1011		printf("[FAIL]\tShadow stack pivot\n");1012		goto out;1013	}1014 1015	if (test_shstk_faults()) {1016		ret = 1;1017		printf("[FAIL]\tShadow stack fault test\n");1018		goto out;1019	}1020 1021	if (test_shstk_violation()) {1022		ret = 1;1023		printf("[FAIL]\tShadow stack violation test\n");1024		goto out;1025	}1026 1027	if (test_gup()) {1028		ret = 1;1029		printf("[FAIL]\tShadow shadow stack gup\n");1030		goto out;1031	}1032 1033	if (test_mprotect()) {1034		ret = 1;1035		printf("[FAIL]\tShadow shadow mprotect test\n");1036		goto out;1037	}1038 1039	if (test_userfaultfd()) {1040		ret = 1;1041		printf("[FAIL]\tUserfaultfd test\n");1042		goto out;1043	}1044 1045	if (test_guard_gap_other_gaps()) {1046		ret = 1;1047		printf("[FAIL]\tGuard gap test, other mappings' gaps\n");1048		goto out;1049	}1050 1051	if (test_guard_gap_new_mappings_gaps()) {1052		ret = 1;1053		printf("[FAIL]\tGuard gap test, placement mapping's gaps\n");1054		goto out;1055	}1056 1057	if (test_ptrace()) {1058		ret = 1;1059		printf("[FAIL]\tptrace test\n");1060	}1061 1062	if (test_32bit()) {1063		ret = 1;1064		printf("[FAIL]\t32 bit test\n");1065		goto out;1066	}1067 1068	if (test_uretprobe()) {1069		ret = 1;1070		printf("[FAIL]\turetprobe test\n");1071		goto out;1072	}1073 1074	return ret;1075 1076out:1077	/*1078	 * Disable shadow stack before the function returns, or there will be a1079	 * shadow stack violation.1080	 */1081	if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {1082		ret = 1;1083		printf("[FAIL]\tDisabling shadow stack failed\n");1084	}1085 1086	return ret;1087}1088#endif1089