xref: /linux/tools/testing/selftests/arm64/bti/test.c (revision 6beeaf48db6c548fcfc2ad32739d33af2fef3a5b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019,2021  Arm Limited
4  * Original author: Dave Martin <Dave.Martin@arm.com>
5  */
6 
7 #include "system.h"
8 
9 #include <stddef.h>
10 #include <linux/errno.h>
11 #include <linux/auxvec.h>
12 #include <linux/signal.h>
13 #include <asm/sigcontext.h>
14 #include <asm/ucontext.h>
15 
16 typedef struct ucontext ucontext_t;
17 
18 #include "btitest.h"
19 #include "compiler.h"
20 #include "signal.h"
21 
22 #define EXPECTED_TESTS 18
23 
24 static volatile unsigned int test_num = 1;
25 static unsigned int test_passed;
26 static unsigned int test_failed;
27 static unsigned int test_skipped;
28 
29 static void fdputs(int fd, const char *str)
30 {
31 	size_t len = 0;
32 	const char *p = str;
33 
34 	while (*p++)
35 		++len;
36 
37 	write(fd, str, len);
38 }
39 
40 static void putstr(const char *str)
41 {
42 	fdputs(1, str);
43 }
44 
45 static void putnum(unsigned int num)
46 {
47 	char c;
48 
49 	if (num / 10)
50 		putnum(num / 10);
51 
52 	c = '0' + (num % 10);
53 	write(1, &c, 1);
54 }
55 
56 #define puttestname(test_name, trampoline_name) do {	\
57 	putstr(test_name);				\
58 	putstr("/");					\
59 	putstr(trampoline_name);			\
60 } while (0)
61 
62 void print_summary(void)
63 {
64 	putstr("# Totals: pass:");
65 	putnum(test_passed);
66 	putstr(" fail:");
67 	putnum(test_failed);
68 	putstr(" xfail:0 xpass:0 skip:");
69 	putnum(test_skipped);
70 	putstr(" error:0\n");
71 }
72 
73 static const char *volatile current_test_name;
74 static const char *volatile current_trampoline_name;
75 static volatile int sigill_expected, sigill_received;
76 
77 static void handler(int n, siginfo_t *si __always_unused,
78 		    void *uc_ __always_unused)
79 {
80 	ucontext_t *uc = uc_;
81 
82 	putstr("# \t[SIGILL in ");
83 	puttestname(current_test_name, current_trampoline_name);
84 	putstr(", BTYPE=");
85 	write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK)
86 			      >> PSR_BTYPE_SHIFT) * 2], 2);
87 	if (!sigill_expected) {
88 		putstr("]\n");
89 		putstr("not ok ");
90 		putnum(test_num);
91 		putstr(" ");
92 		puttestname(current_test_name, current_trampoline_name);
93 		putstr("(unexpected SIGILL)\n");
94 		print_summary();
95 		exit(128 + n);
96 	}
97 
98 	putstr(" (expected)]\n");
99 	sigill_received = 1;
100 	/* zap BTYPE so that resuming the faulting code will work */
101 	uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK;
102 }
103 
104 static int skip_all;
105 
106 static void __do_test(void (*trampoline)(void (*)(void)),
107 		      void (*fn)(void),
108 		      const char *trampoline_name,
109 		      const char *name,
110 		      int expect_sigill)
111 {
112 	if (skip_all) {
113 		test_skipped++;
114 		putstr("ok ");
115 		putnum(test_num);
116 		putstr(" ");
117 		puttestname(name, trampoline_name);
118 		putstr(" # SKIP\n");
119 
120 		return;
121 	}
122 
123 	/* Branch Target exceptions should only happen in BTI binaries: */
124 	if (!BTI)
125 		expect_sigill = 0;
126 
127 	sigill_expected = expect_sigill;
128 	sigill_received = 0;
129 	current_test_name = name;
130 	current_trampoline_name = trampoline_name;
131 
132 	trampoline(fn);
133 
134 	if (expect_sigill && !sigill_received) {
135 		putstr("not ok ");
136 		test_failed++;
137 	} else {
138 		putstr("ok ");
139 		test_passed++;
140 	}
141 	putnum(test_num++);
142 	putstr(" ");
143 	puttestname(name, trampoline_name);
144 	putstr("\n");
145 }
146 
147 #define do_test(expect_sigill_br_x0,					\
148 		expect_sigill_br_x16,					\
149 		expect_sigill_blr,					\
150 		name)							\
151 do {									\
152 	__do_test(call_using_br_x0, name, "call_using_br_x0", #name,	\
153 		  expect_sigill_br_x0);					\
154 	__do_test(call_using_br_x16, name, "call_using_br_x16", #name,	\
155 		  expect_sigill_br_x16);				\
156 	__do_test(call_using_blr, name, "call_using_blr", #name,	\
157 		  expect_sigill_blr);					\
158 } while (0)
159 
160 void start(int *argcp)
161 {
162 	struct sigaction sa;
163 	void *const *p;
164 	const struct auxv_entry {
165 		unsigned long type;
166 		unsigned long val;
167 	} *auxv;
168 	unsigned long hwcap = 0, hwcap2 = 0;
169 
170 	putstr("TAP version 13\n");
171 	putstr("1..");
172 	putnum(EXPECTED_TESTS);
173 	putstr("\n");
174 
175 	/* Gross hack for finding AT_HWCAP2 from the initial process stack: */
176 	p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
177 	/* step over environment */
178 	while (*p++)
179 		;
180 	for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
181 		switch (auxv->type) {
182 		case AT_HWCAP:
183 			hwcap = auxv->val;
184 			break;
185 		case AT_HWCAP2:
186 			hwcap2 = auxv->val;
187 			break;
188 		default:
189 			break;
190 		}
191 	}
192 
193 	if (hwcap & HWCAP_PACA)
194 		putstr("# HWCAP_PACA present\n");
195 	else
196 		putstr("# HWCAP_PACA not present\n");
197 
198 	if (hwcap2 & HWCAP2_BTI) {
199 		putstr("# HWCAP2_BTI present\n");
200 		if (!(hwcap & HWCAP_PACA))
201 			putstr("# Bad hardware?  Expect problems.\n");
202 	} else {
203 		putstr("# HWCAP2_BTI not present\n");
204 		skip_all = 1;
205 	}
206 
207 	putstr("# Test binary");
208 	if (!BTI)
209 		putstr(" not");
210 	putstr(" built for BTI\n");
211 
212 	sa.sa_handler = (sighandler_t)(void *)handler;
213 	sa.sa_flags = SA_SIGINFO;
214 	sigemptyset(&sa.sa_mask);
215 	sigaction(SIGILL, &sa, NULL);
216 	sigaddset(&sa.sa_mask, SIGILL);
217 	sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
218 
219 	do_test(1, 1, 1, nohint_func);
220 	do_test(1, 1, 1, bti_none_func);
221 	do_test(1, 0, 0, bti_c_func);
222 	do_test(0, 0, 1, bti_j_func);
223 	do_test(0, 0, 0, bti_jc_func);
224 	do_test(1, 0, 0, paciasp_func);
225 
226 	print_summary();
227 
228 	if (test_num - 1 != EXPECTED_TESTS)
229 		putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
230 
231 	if (test_failed)
232 		exit(1);
233 	else
234 		exit(0);
235 }
236