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