xref: /linux/tools/testing/selftests/arm64/bti/test.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1314bcbf0SMark Brown // SPDX-License-Identifier: GPL-2.0
2314bcbf0SMark Brown /*
3314bcbf0SMark Brown  * Copyright (C) 2019,2021  Arm Limited
4314bcbf0SMark Brown  * Original author: Dave Martin <Dave.Martin@arm.com>
5314bcbf0SMark Brown  */
6314bcbf0SMark Brown 
7314bcbf0SMark Brown #include "system.h"
8314bcbf0SMark Brown 
9*1c3b6145SMark Brown #include <stdbool.h>
10a1bed090SMark Brown #include <stddef.h>
11314bcbf0SMark Brown #include <linux/errno.h>
12314bcbf0SMark Brown #include <linux/auxvec.h>
13314bcbf0SMark Brown #include <linux/signal.h>
14314bcbf0SMark Brown #include <asm/sigcontext.h>
15314bcbf0SMark Brown #include <asm/ucontext.h>
16314bcbf0SMark Brown 
17314bcbf0SMark Brown typedef struct ucontext ucontext_t;
18314bcbf0SMark Brown 
19314bcbf0SMark Brown #include "btitest.h"
20314bcbf0SMark Brown #include "signal.h"
21314bcbf0SMark Brown 
22314bcbf0SMark Brown #define EXPECTED_TESTS 18
23314bcbf0SMark Brown 
24314bcbf0SMark Brown static volatile unsigned int test_num = 1;
25314bcbf0SMark Brown static unsigned int test_passed;
26314bcbf0SMark Brown static unsigned int test_failed;
27314bcbf0SMark Brown static unsigned int test_skipped;
28314bcbf0SMark Brown 
fdputs(int fd,const char * str)29314bcbf0SMark Brown static void fdputs(int fd, const char *str)
30314bcbf0SMark Brown {
31314bcbf0SMark Brown 	size_t len = 0;
32314bcbf0SMark Brown 	const char *p = str;
33314bcbf0SMark Brown 
34314bcbf0SMark Brown 	while (*p++)
35314bcbf0SMark Brown 		++len;
36314bcbf0SMark Brown 
37314bcbf0SMark Brown 	write(fd, str, len);
38314bcbf0SMark Brown }
39314bcbf0SMark Brown 
putstr(const char * str)40314bcbf0SMark Brown static void putstr(const char *str)
41314bcbf0SMark Brown {
42314bcbf0SMark Brown 	fdputs(1, str);
43314bcbf0SMark Brown }
44314bcbf0SMark Brown 
putnum(unsigned int num)45314bcbf0SMark Brown static void putnum(unsigned int num)
46314bcbf0SMark Brown {
47314bcbf0SMark Brown 	char c;
48314bcbf0SMark Brown 
49314bcbf0SMark Brown 	if (num / 10)
50314bcbf0SMark Brown 		putnum(num / 10);
51314bcbf0SMark Brown 
52314bcbf0SMark Brown 	c = '0' + (num % 10);
53314bcbf0SMark Brown 	write(1, &c, 1);
54314bcbf0SMark Brown }
55314bcbf0SMark Brown 
56314bcbf0SMark Brown #define puttestname(test_name, trampoline_name) do {	\
57314bcbf0SMark Brown 	putstr(test_name);				\
58314bcbf0SMark Brown 	putstr("/");					\
59314bcbf0SMark Brown 	putstr(trampoline_name);			\
60314bcbf0SMark Brown } while (0)
61314bcbf0SMark Brown 
print_summary(void)62314bcbf0SMark Brown void print_summary(void)
63314bcbf0SMark Brown {
64314bcbf0SMark Brown 	putstr("# Totals: pass:");
65314bcbf0SMark Brown 	putnum(test_passed);
66314bcbf0SMark Brown 	putstr(" fail:");
67314bcbf0SMark Brown 	putnum(test_failed);
68314bcbf0SMark Brown 	putstr(" xfail:0 xpass:0 skip:");
69314bcbf0SMark Brown 	putnum(test_skipped);
70314bcbf0SMark Brown 	putstr(" error:0\n");
71314bcbf0SMark Brown }
72314bcbf0SMark Brown 
73314bcbf0SMark Brown static const char *volatile current_test_name;
74314bcbf0SMark Brown static const char *volatile current_trampoline_name;
75314bcbf0SMark Brown static volatile int sigill_expected, sigill_received;
76314bcbf0SMark Brown 
handler(int n,siginfo_t * si __always_unused,void * uc_ __always_unused)77314bcbf0SMark Brown static void handler(int n, siginfo_t *si __always_unused,
78314bcbf0SMark Brown 		    void *uc_ __always_unused)
79314bcbf0SMark Brown {
80314bcbf0SMark Brown 	ucontext_t *uc = uc_;
81314bcbf0SMark Brown 
82314bcbf0SMark Brown 	putstr("# \t[SIGILL in ");
83314bcbf0SMark Brown 	puttestname(current_test_name, current_trampoline_name);
84314bcbf0SMark Brown 	putstr(", BTYPE=");
85314bcbf0SMark Brown 	write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK)
86314bcbf0SMark Brown 			      >> PSR_BTYPE_SHIFT) * 2], 2);
87314bcbf0SMark Brown 	if (!sigill_expected) {
88314bcbf0SMark Brown 		putstr("]\n");
89314bcbf0SMark Brown 		putstr("not ok ");
90314bcbf0SMark Brown 		putnum(test_num);
91314bcbf0SMark Brown 		putstr(" ");
92314bcbf0SMark Brown 		puttestname(current_test_name, current_trampoline_name);
93314bcbf0SMark Brown 		putstr("(unexpected SIGILL)\n");
94314bcbf0SMark Brown 		print_summary();
95314bcbf0SMark Brown 		exit(128 + n);
96314bcbf0SMark Brown 	}
97314bcbf0SMark Brown 
98314bcbf0SMark Brown 	putstr(" (expected)]\n");
99314bcbf0SMark Brown 	sigill_received = 1;
100314bcbf0SMark Brown 	/* zap BTYPE so that resuming the faulting code will work */
101314bcbf0SMark Brown 	uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK;
102314bcbf0SMark Brown }
103314bcbf0SMark Brown 
104*1c3b6145SMark Brown /* Does the system have BTI? */
105*1c3b6145SMark Brown static bool have_bti;
106314bcbf0SMark Brown 
__do_test(void (* trampoline)(void (*)(void)),void (* fn)(void),const char * trampoline_name,const char * name,int expect_sigill)107314bcbf0SMark Brown static void __do_test(void (*trampoline)(void (*)(void)),
108314bcbf0SMark Brown 		      void (*fn)(void),
109314bcbf0SMark Brown 		      const char *trampoline_name,
110314bcbf0SMark Brown 		      const char *name,
111314bcbf0SMark Brown 		      int expect_sigill)
112314bcbf0SMark Brown {
113*1c3b6145SMark Brown 	/*
114*1c3b6145SMark Brown 	 * Branch Target exceptions should only happen for BTI
115*1c3b6145SMark Brown 	 * binaries running on a system with BTI:
116*1c3b6145SMark Brown 	 */
117*1c3b6145SMark Brown 	if (!BTI || !have_bti)
118314bcbf0SMark Brown 		expect_sigill = 0;
119314bcbf0SMark Brown 
120314bcbf0SMark Brown 	sigill_expected = expect_sigill;
121314bcbf0SMark Brown 	sigill_received = 0;
122314bcbf0SMark Brown 	current_test_name = name;
123314bcbf0SMark Brown 	current_trampoline_name = trampoline_name;
124314bcbf0SMark Brown 
125314bcbf0SMark Brown 	trampoline(fn);
126314bcbf0SMark Brown 
127314bcbf0SMark Brown 	if (expect_sigill && !sigill_received) {
128314bcbf0SMark Brown 		putstr("not ok ");
129314bcbf0SMark Brown 		test_failed++;
130314bcbf0SMark Brown 	} else {
131314bcbf0SMark Brown 		putstr("ok ");
132314bcbf0SMark Brown 		test_passed++;
133314bcbf0SMark Brown 	}
134314bcbf0SMark Brown 	putnum(test_num++);
135314bcbf0SMark Brown 	putstr(" ");
136314bcbf0SMark Brown 	puttestname(name, trampoline_name);
137314bcbf0SMark Brown 	putstr("\n");
138314bcbf0SMark Brown }
139314bcbf0SMark Brown 
140314bcbf0SMark Brown #define do_test(expect_sigill_br_x0,					\
141314bcbf0SMark Brown 		expect_sigill_br_x16,					\
142314bcbf0SMark Brown 		expect_sigill_blr,					\
143314bcbf0SMark Brown 		name)							\
144314bcbf0SMark Brown do {									\
145314bcbf0SMark Brown 	__do_test(call_using_br_x0, name, "call_using_br_x0", #name,	\
146314bcbf0SMark Brown 		  expect_sigill_br_x0);					\
147314bcbf0SMark Brown 	__do_test(call_using_br_x16, name, "call_using_br_x16", #name,	\
148314bcbf0SMark Brown 		  expect_sigill_br_x16);				\
149314bcbf0SMark Brown 	__do_test(call_using_blr, name, "call_using_blr", #name,	\
150314bcbf0SMark Brown 		  expect_sigill_blr);					\
151314bcbf0SMark Brown } while (0)
152314bcbf0SMark Brown 
start(int * argcp)153314bcbf0SMark Brown void start(int *argcp)
154314bcbf0SMark Brown {
155314bcbf0SMark Brown 	struct sigaction sa;
156314bcbf0SMark Brown 	void *const *p;
157314bcbf0SMark Brown 	const struct auxv_entry {
158314bcbf0SMark Brown 		unsigned long type;
159314bcbf0SMark Brown 		unsigned long val;
160314bcbf0SMark Brown 	} *auxv;
161314bcbf0SMark Brown 	unsigned long hwcap = 0, hwcap2 = 0;
162314bcbf0SMark Brown 
163314bcbf0SMark Brown 	putstr("TAP version 13\n");
164314bcbf0SMark Brown 	putstr("1..");
165314bcbf0SMark Brown 	putnum(EXPECTED_TESTS);
166314bcbf0SMark Brown 	putstr("\n");
167314bcbf0SMark Brown 
168314bcbf0SMark Brown 	/* Gross hack for finding AT_HWCAP2 from the initial process stack: */
169314bcbf0SMark Brown 	p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
170314bcbf0SMark Brown 	/* step over environment */
171314bcbf0SMark Brown 	while (*p++)
172314bcbf0SMark Brown 		;
173314bcbf0SMark Brown 	for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
174314bcbf0SMark Brown 		switch (auxv->type) {
175314bcbf0SMark Brown 		case AT_HWCAP:
176314bcbf0SMark Brown 			hwcap = auxv->val;
177314bcbf0SMark Brown 			break;
178314bcbf0SMark Brown 		case AT_HWCAP2:
179314bcbf0SMark Brown 			hwcap2 = auxv->val;
180314bcbf0SMark Brown 			break;
181314bcbf0SMark Brown 		default:
182314bcbf0SMark Brown 			break;
183314bcbf0SMark Brown 		}
184314bcbf0SMark Brown 	}
185314bcbf0SMark Brown 
186314bcbf0SMark Brown 	if (hwcap & HWCAP_PACA)
187314bcbf0SMark Brown 		putstr("# HWCAP_PACA present\n");
188314bcbf0SMark Brown 	else
189314bcbf0SMark Brown 		putstr("# HWCAP_PACA not present\n");
190314bcbf0SMark Brown 
191314bcbf0SMark Brown 	if (hwcap2 & HWCAP2_BTI) {
192314bcbf0SMark Brown 		putstr("# HWCAP2_BTI present\n");
193314bcbf0SMark Brown 		if (!(hwcap & HWCAP_PACA))
194314bcbf0SMark Brown 			putstr("# Bad hardware?  Expect problems.\n");
195*1c3b6145SMark Brown 		have_bti = true;
196314bcbf0SMark Brown 	} else {
197314bcbf0SMark Brown 		putstr("# HWCAP2_BTI not present\n");
198*1c3b6145SMark Brown 		have_bti = false;
199314bcbf0SMark Brown 	}
200314bcbf0SMark Brown 
201314bcbf0SMark Brown 	putstr("# Test binary");
202314bcbf0SMark Brown 	if (!BTI)
203314bcbf0SMark Brown 		putstr(" not");
204314bcbf0SMark Brown 	putstr(" built for BTI\n");
205314bcbf0SMark Brown 
206314bcbf0SMark Brown 	sa.sa_handler = (sighandler_t)(void *)handler;
207314bcbf0SMark Brown 	sa.sa_flags = SA_SIGINFO;
208314bcbf0SMark Brown 	sigemptyset(&sa.sa_mask);
209314bcbf0SMark Brown 	sigaction(SIGILL, &sa, NULL);
210314bcbf0SMark Brown 	sigaddset(&sa.sa_mask, SIGILL);
211314bcbf0SMark Brown 	sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
212314bcbf0SMark Brown 
213314bcbf0SMark Brown 	do_test(1, 1, 1, nohint_func);
214314bcbf0SMark Brown 	do_test(1, 1, 1, bti_none_func);
215314bcbf0SMark Brown 	do_test(1, 0, 0, bti_c_func);
216314bcbf0SMark Brown 	do_test(0, 0, 1, bti_j_func);
217314bcbf0SMark Brown 	do_test(0, 0, 0, bti_jc_func);
218314bcbf0SMark Brown 	do_test(1, 0, 0, paciasp_func);
219314bcbf0SMark Brown 
220314bcbf0SMark Brown 	print_summary();
221314bcbf0SMark Brown 
222314bcbf0SMark Brown 	if (test_num - 1 != EXPECTED_TESTS)
223314bcbf0SMark Brown 		putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
224314bcbf0SMark Brown 
225314bcbf0SMark Brown 	if (test_failed)
226314bcbf0SMark Brown 		exit(1);
227314bcbf0SMark Brown 	else
228314bcbf0SMark Brown 		exit(0);
229314bcbf0SMark Brown }
230