| 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, buf: str, size: len); |
| 38 | } |
| 39 | |
| 40 | static void putstr(const char *str) |
| 41 | { |
| 42 | fdputs(fd: 1, str); |
| 43 | } |
| 44 | |
| 45 | static void putnum(unsigned int num) |
| 46 | { |
| 47 | char c; |
| 48 | |
| 49 | if (num / 10) |
| 50 | putnum(num: num / 10); |
| 51 | |
| 52 | c = '0' + (num % 10); |
| 53 | write(fd: 1, buf: &c, size: 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(str: "# Totals: pass:" ); |
| 65 | putnum(num: test_passed); |
| 66 | putstr(str: " fail:" ); |
| 67 | putnum(num: test_failed); |
| 68 | putstr(str: " xfail:0 xpass:0 skip:" ); |
| 69 | putnum(num: test_skipped); |
| 70 | putstr(str: " 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(str: "# \t[SIGILL in " ); |
| 83 | puttestname(current_test_name, current_trampoline_name); |
| 84 | putstr(str: ", BTYPE=" ); |
| 85 | write(1, &"00011011" [((uc->uc_mcontext.pstate & PSR_BTYPE_MASK) |
| 86 | >> PSR_BTYPE_SHIFT) * 2], 2); |
| 87 | if (!sigill_expected) { |
| 88 | putstr(str: "]\n" ); |
| 89 | putstr(str: "not ok " ); |
| 90 | putnum(num: test_num); |
| 91 | putstr(str: " " ); |
| 92 | puttestname(current_test_name, current_trampoline_name); |
| 93 | putstr(str: "(unexpected SIGILL)\n" ); |
| 94 | print_summary(); |
| 95 | exit(n: 128 + n); |
| 96 | } |
| 97 | |
| 98 | putstr(str: " (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(str: "not ok " ); |
| 129 | test_failed++; |
| 130 | } else { |
| 131 | putstr(str: "ok " ); |
| 132 | test_passed++; |
| 133 | } |
| 134 | putnum(num: test_num++); |
| 135 | putstr(str: " " ); |
| 136 | puttestname(name, trampoline_name); |
| 137 | putstr(str: "\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(str: "TAP version 13\n" ); |
| 164 | putstr(str: "1.." ); |
| 165 | putnum(EXPECTED_TESTS); |
| 166 | putstr(str: "\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(str: "# HWCAP_PACA present\n" ); |
| 188 | else |
| 189 | putstr(str: "# HWCAP_PACA not present\n" ); |
| 190 | |
| 191 | if (hwcap2 & HWCAP2_BTI) { |
| 192 | putstr(str: "# HWCAP2_BTI present\n" ); |
| 193 | if (!(hwcap & HWCAP_PACA)) |
| 194 | putstr(str: "# Bad hardware? Expect problems.\n" ); |
| 195 | have_bti = true; |
| 196 | } else { |
| 197 | putstr(str: "# HWCAP2_BTI not present\n" ); |
| 198 | have_bti = false; |
| 199 | } |
| 200 | |
| 201 | putstr(str: "# Test binary" ); |
| 202 | if (!BTI) |
| 203 | putstr(str: " not" ); |
| 204 | putstr(str: " built for BTI\n" ); |
| 205 | |
| 206 | sa.sa_handler = (sighandler_t)(void *)handler; |
| 207 | sa.sa_flags = SA_SIGINFO; |
| 208 | sigemptyset(set: &sa.sa_mask); |
| 209 | sigaction(SIGILL, sa: &sa, NULL); |
| 210 | sigaddset(set: &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(str: "# WARNING - EXPECTED TEST COUNT WRONG\n" ); |
| 224 | |
| 225 | if (test_failed) |
| 226 | exit(n: 1); |
| 227 | else |
| 228 | exit(n: 0); |
| 229 | } |
| 230 | |