Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/bti/test.c
26299 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2019,2021 Arm Limited
4
* Original author: Dave Martin <[email protected]>
5
*/
6
7
#include "system.h"
8
9
#include <stdbool.h>
10
#include <stddef.h>
11
#include <linux/errno.h>
12
#include <linux/auxvec.h>
13
#include <linux/signal.h>
14
#include <asm/sigcontext.h>
15
#include <asm/ucontext.h>
16
17
typedef struct ucontext ucontext_t;
18
19
#include "btitest.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
/* Does the system have BTI? */
105
static bool have_bti;
106
107
static void __do_test(void (*trampoline)(void (*)(void)),
108
void (*fn)(void),
109
const char *trampoline_name,
110
const char *name,
111
int expect_sigill)
112
{
113
/*
114
* Branch Target exceptions should only happen for BTI
115
* binaries running on a system with BTI:
116
*/
117
if (!BTI || !have_bti)
118
expect_sigill = 0;
119
120
sigill_expected = expect_sigill;
121
sigill_received = 0;
122
current_test_name = name;
123
current_trampoline_name = trampoline_name;
124
125
trampoline(fn);
126
127
if (expect_sigill && !sigill_received) {
128
putstr("not ok ");
129
test_failed++;
130
} else {
131
putstr("ok ");
132
test_passed++;
133
}
134
putnum(test_num++);
135
putstr(" ");
136
puttestname(name, trampoline_name);
137
putstr("\n");
138
}
139
140
#define do_test(expect_sigill_br_x0, \
141
expect_sigill_br_x16, \
142
expect_sigill_blr, \
143
name) \
144
do { \
145
__do_test(call_using_br_x0, name, "call_using_br_x0", #name, \
146
expect_sigill_br_x0); \
147
__do_test(call_using_br_x16, name, "call_using_br_x16", #name, \
148
expect_sigill_br_x16); \
149
__do_test(call_using_blr, name, "call_using_blr", #name, \
150
expect_sigill_blr); \
151
} while (0)
152
153
void start(int *argcp)
154
{
155
struct sigaction sa;
156
void *const *p;
157
const struct auxv_entry {
158
unsigned long type;
159
unsigned long val;
160
} *auxv;
161
unsigned long hwcap = 0, hwcap2 = 0;
162
163
putstr("TAP version 13\n");
164
putstr("1..");
165
putnum(EXPECTED_TESTS);
166
putstr("\n");
167
168
/* Gross hack for finding AT_HWCAP2 from the initial process stack: */
169
p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
170
/* step over environment */
171
while (*p++)
172
;
173
for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
174
switch (auxv->type) {
175
case AT_HWCAP:
176
hwcap = auxv->val;
177
break;
178
case AT_HWCAP2:
179
hwcap2 = auxv->val;
180
break;
181
default:
182
break;
183
}
184
}
185
186
if (hwcap & HWCAP_PACA)
187
putstr("# HWCAP_PACA present\n");
188
else
189
putstr("# HWCAP_PACA not present\n");
190
191
if (hwcap2 & HWCAP2_BTI) {
192
putstr("# HWCAP2_BTI present\n");
193
if (!(hwcap & HWCAP_PACA))
194
putstr("# Bad hardware? Expect problems.\n");
195
have_bti = true;
196
} else {
197
putstr("# HWCAP2_BTI not present\n");
198
have_bti = false;
199
}
200
201
putstr("# Test binary");
202
if (!BTI)
203
putstr(" not");
204
putstr(" built for BTI\n");
205
206
sa.sa_handler = (sighandler_t)(void *)handler;
207
sa.sa_flags = SA_SIGINFO;
208
sigemptyset(&sa.sa_mask);
209
sigaction(SIGILL, &sa, NULL);
210
sigaddset(&sa.sa_mask, SIGILL);
211
sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
212
213
do_test(1, 1, 1, nohint_func);
214
do_test(1, 1, 1, bti_none_func);
215
do_test(1, 0, 0, bti_c_func);
216
do_test(0, 0, 1, bti_j_func);
217
do_test(0, 0, 0, bti_jc_func);
218
do_test(1, 0, 0, paciasp_func);
219
220
print_summary();
221
222
if (test_num - 1 != EXPECTED_TESTS)
223
putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
224
225
if (test_failed)
226
exit(1);
227
else
228
exit(0);
229
}
230
231