xref: /linux/tools/testing/selftests/arm64/signal/testcases/gcs_write_fault.c (revision c771600c6af14749609b49565ffb4cac2959710d)
1*794b64caSMark Brown // SPDX-License-Identifier: GPL-2.0
2*794b64caSMark Brown /*
3*794b64caSMark Brown  * Copyright (C) 2023 ARM Limited
4*794b64caSMark Brown  */
5*794b64caSMark Brown 
6*794b64caSMark Brown #include <errno.h>
7*794b64caSMark Brown #include <signal.h>
8*794b64caSMark Brown #include <unistd.h>
9*794b64caSMark Brown 
10*794b64caSMark Brown #include <sys/mman.h>
11*794b64caSMark Brown #include <sys/prctl.h>
12*794b64caSMark Brown 
13*794b64caSMark Brown #include "test_signals_utils.h"
14*794b64caSMark Brown #include "testcases.h"
15*794b64caSMark Brown 
16*794b64caSMark Brown static uint64_t *gcs_page;
17*794b64caSMark Brown 
18*794b64caSMark Brown #ifndef __NR_map_shadow_stack
19*794b64caSMark Brown #define __NR_map_shadow_stack 453
20*794b64caSMark Brown #endif
21*794b64caSMark Brown 
22*794b64caSMark Brown static bool alloc_gcs(struct tdescr *td)
23*794b64caSMark Brown {
24*794b64caSMark Brown 	long page_size = sysconf(_SC_PAGE_SIZE);
25*794b64caSMark Brown 
26*794b64caSMark Brown 	gcs_page = (void *)syscall(__NR_map_shadow_stack, 0,
27*794b64caSMark Brown 				   page_size, 0);
28*794b64caSMark Brown 	if (gcs_page == MAP_FAILED) {
29*794b64caSMark Brown 		fprintf(stderr, "Failed to map %ld byte GCS: %d\n",
30*794b64caSMark Brown 			page_size, errno);
31*794b64caSMark Brown 		return false;
32*794b64caSMark Brown 	}
33*794b64caSMark Brown 
34*794b64caSMark Brown 	return true;
35*794b64caSMark Brown }
36*794b64caSMark Brown 
37*794b64caSMark Brown static int gcs_write_fault_trigger(struct tdescr *td)
38*794b64caSMark Brown {
39*794b64caSMark Brown 	/* Verify that the page is readable (ie, not completely unmapped) */
40*794b64caSMark Brown 	fprintf(stderr, "Read value 0x%lx\n", gcs_page[0]);
41*794b64caSMark Brown 
42*794b64caSMark Brown 	/* A regular write should trigger a fault */
43*794b64caSMark Brown 	gcs_page[0] = EINVAL;
44*794b64caSMark Brown 
45*794b64caSMark Brown 	return 0;
46*794b64caSMark Brown }
47*794b64caSMark Brown 
48*794b64caSMark Brown static int gcs_write_fault_signal(struct tdescr *td, siginfo_t *si,
49*794b64caSMark Brown 				  ucontext_t *uc)
50*794b64caSMark Brown {
51*794b64caSMark Brown 	ASSERT_GOOD_CONTEXT(uc);
52*794b64caSMark Brown 
53*794b64caSMark Brown 	return 1;
54*794b64caSMark Brown }
55*794b64caSMark Brown 
56*794b64caSMark Brown 
57*794b64caSMark Brown struct tdescr tde = {
58*794b64caSMark Brown 	.name = "GCS write fault",
59*794b64caSMark Brown 	.descr = "Normal writes to a GCS segfault",
60*794b64caSMark Brown 	.feats_required = FEAT_GCS,
61*794b64caSMark Brown 	.timeout = 3,
62*794b64caSMark Brown 	.sig_ok = SIGSEGV,
63*794b64caSMark Brown 	.sanity_disabled = true,
64*794b64caSMark Brown 	.init = alloc_gcs,
65*794b64caSMark Brown 	.trigger = gcs_write_fault_trigger,
66*794b64caSMark Brown 	.run = gcs_write_fault_signal,
67*794b64caSMark Brown };
68