Add a simple selftest for exercising the new map_shadow_stack syscall. Co-developed-by: Yu, Yu-cheng <yu-cheng.yu@xxxxxxxxx> Signed-off-by: Yu, Yu-cheng <yu-cheng.yu@xxxxxxxxx> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@xxxxxxxxx> --- v1: - New patch. tools/testing/selftests/x86/Makefile | 9 ++- .../selftests/x86/test_map_shadow_stack.c | 75 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/test_map_shadow_stack.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 8a1f62ab3c8e..9114943336f9 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -9,11 +9,13 @@ UNAME_M := $(shell uname -m) CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) +CAN_BUILD_WITH_SHSTK := $(shell ./check_cc.sh $(CC) trivial_program.c -mshstk -fcf-protection) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ test_vsyscall mov_ss_trap \ - syscall_arg_fault fsgsbase_restore sigaltstack + syscall_arg_fault fsgsbase_restore sigaltstack \ + test_map_shadow_stack TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer @@ -105,3 +107,8 @@ $(OUTPUT)/test_syscall_vdso_32: thunks_32.S # state. $(OUTPUT)/check_initial_reg_state_32: CFLAGS += -Wl,-ereal_start -static $(OUTPUT)/check_initial_reg_state_64: CFLAGS += -Wl,-ereal_start -static + +ifeq ($(CAN_BUILD_WITH_SHSTK),1) +$(OUTPUT)/test_map_shadow_stack_64: CFLAGS += -mshstk -fcf-protection +$(OUTPUT)/test_map_shadow_stack_32: CFLAGS += -mshstk -fcf-protection +endif \ No newline at end of file diff --git a/tools/testing/selftests/x86/test_map_shadow_stack.c b/tools/testing/selftests/x86/test_map_shadow_stack.c new file mode 100644 index 000000000000..dfd94ef0176d --- /dev/null +++ b/tools/testing/selftests/x86/test_map_shadow_stack.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include <sys/syscall.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdbool.h> +#include <x86intrin.h> + +#define SS_SIZE 0x200000 + +void *create_shstk(void) +{ + return (void *)syscall(__NR_map_shadow_stack, SS_SIZE, SHADOW_STACK_SET_TOKEN); +} + +#if (__GNUC__ < 8) || (__GNUC__ == 8 && __GNUC_MINOR__ < 5) +int main(int argc, char *argv[]) +{ + printf("SKIP: compiler does not support CET."); + return 0; +} +#else +void try_shstk(unsigned long new_ssp) +{ + unsigned long ssp0, ssp1; + + printf("pid=%d\n", getpid()); + printf("new_ssp = %lx, *new_ssp = %lx\n", + new_ssp, *((unsigned long *)new_ssp)); + + ssp0 = _get_ssp(); + printf("changing ssp from %lx to %lx\n", ssp0, new_ssp); + + /* Make sure is aligned to 8 bytes */ + if ((ssp0 & 0xf) != 0) + ssp0 &= -8; + + asm volatile("rstorssp (%0)\n":: "r" (new_ssp)); + asm volatile("saveprevssp"); + ssp1 = _get_ssp(); + printf("ssp is now %lx\n", ssp1); + + ssp0 -= 8; + asm volatile("rstorssp (%0)\n":: "r" (ssp0)); + asm volatile("saveprevssp"); +} + +int main(int argc, char *argv[]) +{ + void *shstk; + + if (!_get_ssp()) { + printf("SKIP: shadow stack disabled."); + return 0; + } + + shstk = create_shstk(); + if (shstk == MAP_FAILED) { + printf("FAIL: Error creating shadow stack: %d\n", errno); + return 1; + } + try_shstk((unsigned long)shstk + SS_SIZE - 8); + + printf("PASS.\n"); + return 0; +} +#endif -- 2.17.1