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 <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 = '' + (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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.