| 1 | #include <stdint.h> |
| 2 | #include <assert.h> |
| 3 | #include <stdio.h> |
| 4 | #include <stdlib.h> |
| 5 | #include "pauth.h" |
| 6 | |
| 7 | #define TESTS 1000 |
| 8 | |
| 9 | int main() |
| 10 | { |
| 11 | char base[TESTS]; |
| 12 | int i, count = 0; |
| 13 | float perc; |
| 14 | int pac_feature = get_pac_feature(); |
| 15 | |
| 16 | /* |
| 17 | * Exit if no PAuth or FEAT_FPAC, which will SIGILL on AUTIA failure |
| 18 | * rather than return an error for us to check below. |
| 19 | */ |
| 20 | if (pac_feature == 0 || pac_feature >= 4) { |
| 21 | return 0; |
| 22 | } |
| 23 | |
| 24 | for (i = 0; i < TESTS; i++) { |
| 25 | uintptr_t in, x, y; |
| 26 | |
| 27 | in = i + (uintptr_t) base; |
| 28 | |
| 29 | asm("mov %0, %[in]\n\t" |
| 30 | "pacia %0, sp\n\t" |
| 31 | "eor %0, %0, #4\n\t" /* corrupt single bit */ |
| 32 | "mov %1, %0\n\t" |
| 33 | "autia %1, sp\n\t" /* validate corrupted pointer */ |
| 34 | "xpaci %0\n\t" /* strip pac from corrupted pointer */ |
| 35 | : /* out */ "=r"(x), "=r"(y) |
| 36 | : /* in */ [in] "r" (in) |
| 37 | : /* clobbers */); |
| 38 | |
| 39 | /* |
| 40 | * Once stripped, the corrupted pointer is of the form 0x0000...wxyz. |
| 41 | * We expect the autia to indicate failure, producing a pointer of the |
| 42 | * form 0x000e....wxyz. Use xpaci and != for the test, rather than |
| 43 | * extracting explicit bits from the top, because the location of the |
| 44 | * error code "e" depends on the configuration of virtual memory. |
| 45 | */ |
| 46 | if (x != y) { |
| 47 | count++; |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | perc = (float) count / (float) TESTS; |
| 52 | printf("Checks Passed: %0.2f%%\n", perc * 100.0); |
| 53 | assert(perc > 0.95); |
| 54 | return 0; |
| 55 | } |