| 1 | #include <stdint.h> |
| 2 | #include <signal.h> |
| 3 | #include <stdlib.h> |
| 4 | #include <assert.h> |
| 5 | #include "pauth.h" |
| 6 | |
| 7 | |
| 8 | static void sigill(int sig, siginfo_t *info, void *vuc) |
| 9 | { |
| 10 | ucontext_t *uc = vuc; |
| 11 | uint64_t test; |
| 12 | |
| 13 | /* There is only one insn below that is allowed to fault. */ |
| 14 | asm volatile("adr %0, auth2_insn" : "=r"(test)); |
| 15 | assert(test == uc->uc_mcontext.pc); |
| 16 | exit(0); |
| 17 | } |
| 18 | |
| 19 | static int pac_feature; |
| 20 | |
| 21 | void do_test(uint64_t value) |
| 22 | { |
| 23 | uint64_t salt1, salt2; |
| 24 | uint64_t encode, decode; |
| 25 | |
| 26 | /* |
| 27 | * With TBI enabled and a 48-bit VA, there are 7 bits of auth, |
| 28 | * and so a 1/128 chance of encode = pac(value,key,salt) producing |
| 29 | * an auth for which leaves value unchanged. |
| 30 | * Iterate until we find a salt for which encode != value. |
| 31 | */ |
| 32 | for (salt1 = 1; ; salt1++) { |
| 33 | asm volatile("pacda %0, %2" : "=r"(encode) : "0"(value), "r"(salt1)); |
| 34 | if (encode != value) { |
| 35 | break; |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | /* A valid salt must produce a valid authorization. */ |
| 40 | asm volatile("autda %0, %2" : "=r"(decode) : "0"(encode), "r"(salt1)); |
| 41 | assert(decode == value); |
| 42 | |
| 43 | /* |
| 44 | * An invalid salt usually fails authorization, but again there |
| 45 | * is a chance of choosing another salt that works. |
| 46 | * Iterate until we find another salt which does fail. |
| 47 | * |
| 48 | * With FEAT_FPAC, this will SIGILL instead of producing a result. |
| 49 | */ |
| 50 | for (salt2 = salt1 + 1; ; salt2++) { |
| 51 | asm volatile("auth2_insn: autda %0, %2" |
| 52 | : "=r"(decode) : "0"(encode), "r"(salt2)); |
| 53 | if (decode != value) { |
| 54 | break; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | assert(pac_feature < 4); /* No FEAT_FPAC */ |
| 59 | |
| 60 | /* The VA bits, bit 55, and the TBI bits, should be unchanged. */ |
| 61 | assert(((decode ^ value) & 0xff80ffffffffffffull) == 0); |
| 62 | |
| 63 | /* |
| 64 | * Without FEAT_Pauth2, bits [54:53] are an error indicator based on |
| 65 | * the key used; the DA key above is keynumber 0, so error == 0b01. |
| 66 | * Otherwise, bit 55 of the original is sign-extended into the rest |
| 67 | * of the auth. |
| 68 | */ |
| 69 | if (pac_feature < 3) { |
| 70 | if ((value >> 55) & 1) { |
| 71 | assert(((decode >> 48) & 0xff) == 0b10111111); |
| 72 | } else { |
| 73 | assert(((decode >> 48) & 0xff) == 0b00100000); |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | int main() |
| 79 | { |
| 80 | static const struct sigaction sa = { |
| 81 | .sa_sigaction = sigill, |
| 82 | .sa_flags = SA_SIGINFO |
| 83 | }; |
| 84 | |
| 85 | pac_feature = get_pac_feature(); |
| 86 | assert(pac_feature != 0); |
| 87 | |
| 88 | if (pac_feature >= 4) { |
| 89 | /* FEAT_FPAC */ |
| 90 | sigaction(SIGILL, &sa, NULL); |
| 91 | } |
| 92 | |
| 93 | do_test(0); |
| 94 | do_test(0xda004acedeadbeefull); |
| 95 | return 0; |
| 96 | } |