xref: /linux/tools/testing/selftests/arm64/signal/testcases/gcs_prot_none_fault.c (revision 8457669db968c98edb781892d73fa559e1efcbd4)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2026 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 static bool post_mprotect;
18 
19 #ifndef __NR_map_shadow_stack
20 #define __NR_map_shadow_stack 453
21 #endif
22 
alloc_gcs(struct tdescr * td)23 static bool alloc_gcs(struct tdescr *td)
24 {
25 	long page_size = sysconf(_SC_PAGE_SIZE);
26 
27 	gcs_page = (void *)syscall(__NR_map_shadow_stack, 0,
28 				   page_size, 0);
29 	if (gcs_page == MAP_FAILED) {
30 		fprintf(stderr, "Failed to map %ld byte GCS: %d\n",
31 			page_size, errno);
32 		return false;
33 	}
34 
35 	return true;
36 }
37 
gcs_prot_none_fault_trigger(struct tdescr * td)38 static int gcs_prot_none_fault_trigger(struct tdescr *td)
39 {
40 	/* Verify that the page is readable (ie, not completely unmapped) */
41 	fprintf(stderr, "Read value 0x%lx\n", gcs_page[0]);
42 
43 	if (mprotect(gcs_page, sysconf(_SC_PAGE_SIZE), PROT_NONE) != 0) {
44 		fprintf(stderr, "mprotect(PROT_NONE) failed: %d\n", errno);
45 		return 0;
46 	}
47 	post_mprotect = true;
48 
49 	/* This should trigger a fault if PROT_NONE is honoured for the GCS page */
50 	fprintf(stderr, "Read value after mprotect(PROT_NONE) 0x%lx\n", gcs_page[0]);
51 	return 0;
52 }
53 
gcs_prot_none_fault_signal(struct tdescr * td,siginfo_t * si,ucontext_t * uc)54 static int gcs_prot_none_fault_signal(struct tdescr *td, siginfo_t *si,
55 				      ucontext_t *uc)
56 {
57 	ASSERT_GOOD_CONTEXT(uc);
58 
59 	/* A fault before mprotect(PROT_NONE) is unexpected. */
60 	if (!post_mprotect)
61 		return 0;
62 
63 	return 1;
64 }
65 
66 struct tdescr tde = {
67 	.name = "GCS PROT_NONE fault",
68 	.descr = "Read from GCS after mprotect(PROT_NONE) segfaults",
69 	.feats_required = FEAT_GCS,
70 	.timeout = 3,
71 	.sig_ok = SIGSEGV,
72 	.sanity_disabled = true,
73 	.init = alloc_gcs,
74 	.trigger = gcs_prot_none_fault_trigger,
75 	.run = gcs_prot_none_fault_signal,
76 };
77