| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | |
| 3 | #include "gcs.h" |
| 4 | |
| 5 | #define IN_PROGRESS(X) ((uint64_t)(X) | 5) |
| 6 | #define CAP(X) (((uint64_t)(X) & ~0xfff) + 1) |
| 7 | |
| 8 | static uint64_t * __attribute__((noinline)) recurse(size_t index) |
| 9 | { |
| 10 | if (index == 0) { |
| 11 | return gcspr(); |
| 12 | } |
| 13 | return recurse(index - 1); |
| 14 | } |
| 15 | |
| 16 | int main() |
| 17 | { |
| 18 | void *tmp; |
| 19 | uint64_t *alt_stack, *alt_cap; |
| 20 | uint64_t *orig_pr, *orig_cap; |
| 21 | uint64_t *bottom; |
| 22 | size_t pagesize = getpagesize(); |
| 23 | size_t words; |
| 24 | |
| 25 | enable_gcs(0); |
| 26 | orig_pr = gcspr(); |
| 27 | |
| 28 | /* Allocate a guard page before and after. */ |
| 29 | tmp = mmap(0, 3 * pagesize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); |
| 30 | assert(tmp != MAP_FAILED); |
| 31 | |
| 32 | /* map_shadow_stack won't replace existing mappings */ |
| 33 | munmap(tmp + pagesize, pagesize); |
| 34 | |
| 35 | /* Allocate a new stack between the guards. */ |
| 36 | alt_stack = (uint64_t *) |
| 37 | syscall(__NR_map_shadow_stack, tmp + pagesize, pagesize, |
| 38 | SHADOW_STACK_SET_TOKEN); |
| 39 | assert(alt_stack == tmp + pagesize); |
| 40 | |
| 41 | words = pagesize / 8; |
| 42 | alt_cap = alt_stack + words - 1; |
| 43 | |
| 44 | /* SHADOW_STACK_SET_TOKEN set the cap. */ |
| 45 | assert(*alt_cap == CAP(alt_cap)); |
| 46 | |
| 47 | /* Swap to the alt stack, one step at a time. */ |
| 48 | gcsss1(alt_cap); |
| 49 | |
| 50 | assert(gcspr() == alt_cap); |
| 51 | assert(*alt_cap == IN_PROGRESS(orig_pr)); |
| 52 | |
| 53 | orig_cap = gcsss2(); |
| 54 | |
| 55 | assert(orig_cap == orig_pr - 1); |
| 56 | assert(*orig_cap == CAP(orig_cap)); |
| 57 | assert(gcspr() == alt_stack + words); |
| 58 | |
| 59 | /* We should be able to use the whole stack. */ |
| 60 | bottom = recurse(words - 1); |
| 61 | assert(bottom == alt_stack); |
| 62 | |
| 63 | /* We should be back where we started. */ |
| 64 | assert(gcspr() == alt_stack + words); |
| 65 | |
| 66 | /* Swap back to the original stack. */ |
| 67 | gcsss1(orig_cap); |
| 68 | tmp = gcsss2(); |
| 69 | |
| 70 | assert(gcspr() == orig_pr); |
| 71 | assert(tmp == alt_cap); |
| 72 | |
| 73 | exit(0); |
| 74 | } |