mirror of https://gitlab.com/qemu-project/qemu
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
1.8 KiB
C
75 lines
1.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "gcs.h"
|
|
|
|
#define IN_PROGRESS(X) ((uint64_t)(X) | 5)
|
|
#define CAP(X) (((uint64_t)(X) & ~0xfff) + 1)
|
|
|
|
static uint64_t * __attribute__((noinline)) recurse(size_t index)
|
|
{
|
|
if (index == 0) {
|
|
return gcspr();
|
|
}
|
|
return recurse(index - 1);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
void *tmp;
|
|
uint64_t *alt_stack, *alt_cap;
|
|
uint64_t *orig_pr, *orig_cap;
|
|
uint64_t *bottom;
|
|
size_t pagesize = getpagesize();
|
|
size_t words;
|
|
|
|
enable_gcs(0);
|
|
orig_pr = gcspr();
|
|
|
|
/* Allocate a guard page before and after. */
|
|
tmp = mmap(0, 3 * pagesize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
|
assert(tmp != MAP_FAILED);
|
|
|
|
/* map_shadow_stack won't replace existing mappings */
|
|
munmap(tmp + pagesize, pagesize);
|
|
|
|
/* Allocate a new stack between the guards. */
|
|
alt_stack = (uint64_t *)
|
|
syscall(__NR_map_shadow_stack, tmp + pagesize, pagesize,
|
|
SHADOW_STACK_SET_TOKEN);
|
|
assert(alt_stack == tmp + pagesize);
|
|
|
|
words = pagesize / 8;
|
|
alt_cap = alt_stack + words - 1;
|
|
|
|
/* SHADOW_STACK_SET_TOKEN set the cap. */
|
|
assert(*alt_cap == CAP(alt_cap));
|
|
|
|
/* Swap to the alt stack, one step at a time. */
|
|
gcsss1(alt_cap);
|
|
|
|
assert(gcspr() == alt_cap);
|
|
assert(*alt_cap == IN_PROGRESS(orig_pr));
|
|
|
|
orig_cap = gcsss2();
|
|
|
|
assert(orig_cap == orig_pr - 1);
|
|
assert(*orig_cap == CAP(orig_cap));
|
|
assert(gcspr() == alt_stack + words);
|
|
|
|
/* We should be able to use the whole stack. */
|
|
bottom = recurse(words - 1);
|
|
assert(bottom == alt_stack);
|
|
|
|
/* We should be back where we started. */
|
|
assert(gcspr() == alt_stack + words);
|
|
|
|
/* Swap back to the original stack. */
|
|
gcsss1(orig_cap);
|
|
tmp = gcsss2();
|
|
|
|
assert(gcspr() == orig_pr);
|
|
assert(tmp == alt_cap);
|
|
|
|
exit(0);
|
|
}
|