diff options
Diffstat (limited to 'test/shadowcallstack')
-rw-r--r-- | test/shadowcallstack/CMakeLists.txt | 21 | ||||
-rw-r--r-- | test/shadowcallstack/init.c | 12 | ||||
-rw-r--r-- | test/shadowcallstack/libc_support.h | 41 | ||||
-rw-r--r-- | test/shadowcallstack/lit.cfg | 23 | ||||
-rw-r--r-- | test/shadowcallstack/lit.site.cfg.in | 12 | ||||
-rw-r--r-- | test/shadowcallstack/minimal_runtime.h | 43 | ||||
-rw-r--r-- | test/shadowcallstack/overflow-aarch64.c | 5 | ||||
-rw-r--r-- | test/shadowcallstack/overflow-x86_64.c | 5 | ||||
-rw-r--r-- | test/shadowcallstack/overflow.c | 39 |
9 files changed, 201 insertions, 0 deletions
diff --git a/test/shadowcallstack/CMakeLists.txt b/test/shadowcallstack/CMakeLists.txt new file mode 100644 index 000000000000..ab2b18819d49 --- /dev/null +++ b/test/shadowcallstack/CMakeLists.txt @@ -0,0 +1,21 @@ +set(TEST_ARCH ${SHADOWCALLSTACK_SUPPORTED_ARCH}) + +set(SHADOWCALLSTACK_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(SHADOWCALLSTACK_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +set(SHADOWCALLSTACK_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) + +foreach(arch ${SHADOWCALLSTACK_SUPPORTED_ARCH}) + set(SANITIZER_COMMON_TEST_TARGET_ARCH ${arch}) + get_test_cc_for_arch(${arch} + SHADOWSTACK_TEST_TARGET_CC SHADOWSTACK_TEST_TARGET_CFLAGS) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${arch}/lit.site.cfg) + list(APPEND SHADOWCALLSTACK_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${arch}) +endforeach() + +add_lit_testsuite(check-shadowcallstack "Running the ShadowCallStack tests" + ${SHADOWCALLSTACK_TESTSUITES} + DEPENDS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +set_target_properties(check-shadowcallstack PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/shadowcallstack/init.c b/test/shadowcallstack/init.c new file mode 100644 index 000000000000..a406e1b140fc --- /dev/null +++ b/test/shadowcallstack/init.c @@ -0,0 +1,12 @@ +// RUN: %clang_scs %s -o %t +// RUN: %run %t + +// Basic smoke test for the runtime + +#include "libc_support.h" +#include "minimal_runtime.h" + +int scs_main(void) { + scs_fputs_stdout("In main.\n"); + return 0; +} diff --git a/test/shadowcallstack/libc_support.h b/test/shadowcallstack/libc_support.h new file mode 100644 index 000000000000..5d89aab645a9 --- /dev/null +++ b/test/shadowcallstack/libc_support.h @@ -0,0 +1,41 @@ +// This header provides replacements for certain libc functions. It is necessary +// in order to safely run the tests on aarch64, because the system libc might +// not have been compiled with -ffixed-x18. + +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#ifdef __aarch64__ + +size_t scs_strlen(const char *p) { + size_t retval = 0; + while (*p++) + retval++; + return retval; +} + +// We mark this function as noinline to make sure that its callers do not +// become leaf functions as a result of inlining. This is because we want to +// make sure that we generate the correct code for non-leaf functions. + +__attribute__((noinline)) void scs_fputs_stdout(const char *p) { + __asm__ __volatile__( + "mov x0, #1\n" // stdout + "mov x1, %0\n" + "mov x2, %1\n" + "mov x8, #64\n" // write + "svc #0\n" ::"r"(p), + "r"(scs_strlen(p)) + : "x0", "x1", "x2", "x8"); +} + +#else + +__attribute__((noinline)) void scs_fputs_stdout(const char *p) { + fputs(p, stdout); +} + +#endif diff --git a/test/shadowcallstack/lit.cfg b/test/shadowcallstack/lit.cfg new file mode 100644 index 000000000000..313cd2b8eff3 --- /dev/null +++ b/test/shadowcallstack/lit.cfg @@ -0,0 +1,23 @@ +# -*- Python -*- + +import os + +# Setup config name. +config.name = 'ShadowCallStack' + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Test suffixes. +config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test'] + +# Add clang substitutions. +config.substitutions.append( ("%clang_noscs ", config.clang + ' -O0 -fno-sanitize=shadow-call-stack ' + config.target_cflags + ' ') ) + +scs_arch_cflags = config.target_cflags +if config.target_arch == 'aarch64': + scs_arch_cflags += ' -ffixed-x18 ' +config.substitutions.append( ("%clang_scs ", config.clang + ' -O0 -fsanitize=shadow-call-stack ' + scs_arch_cflags + ' ') ) + +if config.host_os not in ['Linux'] or config.target_arch not in ['x86_64', 'aarch64']: + config.unsupported = True diff --git a/test/shadowcallstack/lit.site.cfg.in b/test/shadowcallstack/lit.site.cfg.in new file mode 100644 index 000000000000..aa8913e84cb8 --- /dev/null +++ b/test/shadowcallstack/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@SHADOWCALLSTACK_TEST_CONFIG_SUFFIX@" +config.target_cflags = "@SHADOWCALLSTACK_TEST_TARGET_CFLAGS@" +config.target_arch = "@SHADOWCALLSTACK_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@SHADOWCALLSTACK_LIT_SOURCE_DIR@/lit.cfg") diff --git a/test/shadowcallstack/minimal_runtime.h b/test/shadowcallstack/minimal_runtime.h new file mode 100644 index 000000000000..f36fa5a7d245 --- /dev/null +++ b/test/shadowcallstack/minimal_runtime.h @@ -0,0 +1,43 @@ +// A shadow call stack runtime is not yet included with compiler-rt, provide a +// minimal runtime to allocate a shadow call stack and assign an +// architecture-specific register to point at it. + +#pragma once + +#ifdef __x86_64__ +#include <asm/prctl.h> +int arch_prctl(int code, void *addr); +#endif +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/prctl.h> + +#include "libc_support.h" + +__attribute__((no_sanitize("shadow-call-stack"))) +static void __shadowcallstack_init() { + void *stack = mmap(NULL, 8192, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (stack == MAP_FAILED) + abort(); + +#if defined(__x86_64__) + if (arch_prctl(ARCH_SET_GS, stack)) + abort(); +#elif defined(__aarch64__) + __asm__ __volatile__("mov x18, %0" ::"r"(stack)); +#else +#error Unsupported platform +#endif +} + +int scs_main(void); + +__attribute__((no_sanitize("shadow-call-stack"))) int main(void) { + __shadowcallstack_init(); + + // We can't simply return scs_main() because scs_main might have corrupted our + // return address for testing purposes (see overflow.c), so we need to exit + // ourselves. + exit(scs_main()); +} diff --git a/test/shadowcallstack/overflow-aarch64.c b/test/shadowcallstack/overflow-aarch64.c new file mode 100644 index 000000000000..8da798164fe7 --- /dev/null +++ b/test/shadowcallstack/overflow-aarch64.c @@ -0,0 +1,5 @@ +// See overflow.c for a description. + +// REQUIRES: aarch64-target-arch +// RUN: %clang_scs %S/overflow.c -o %t -DITERATIONS=12 +// RUN: %run %t | FileCheck %S/overflow.c diff --git a/test/shadowcallstack/overflow-x86_64.c b/test/shadowcallstack/overflow-x86_64.c new file mode 100644 index 000000000000..38bb13a969a3 --- /dev/null +++ b/test/shadowcallstack/overflow-x86_64.c @@ -0,0 +1,5 @@ +// See overflow.c for a description. + +// REQUIRES: x86_64-target-arch +// RUN: %clang_scs %S/overflow.c -o %t -DITERATIONS=12 +// RUN: not --crash %run %t diff --git a/test/shadowcallstack/overflow.c b/test/shadowcallstack/overflow.c new file mode 100644 index 000000000000..8c3d50c5917f --- /dev/null +++ b/test/shadowcallstack/overflow.c @@ -0,0 +1,39 @@ +// Test that a stack overflow fails as expected + +// RUN: %clang_noscs %s -o %t -DITERATIONS=3 +// RUN: %run %t | FileCheck %s +// RUN: %clang_noscs %s -o %t -DITERATIONS=12 +// RUN: %run %t | FileCheck -check-prefix=OVERFLOW_SUCCESS %s + +// RUN: %clang_scs %s -o %t -DITERATIONS=3 +// RUN: %run %t | FileCheck %s + +// The behavioral check for SCS + overflow lives in the tests overflow-x86_64.c +// and overflow-aarch64.c. This is because the expected behavior is different +// between the two platforms. On x86_64 we crash because the comparison between +// the shadow call stack and the regular stack fails. On aarch64 there is no +// comparison, we just load the return address from the shadow call stack. So we +// just expect not to see the output from print_and_exit. + +#include <stdio.h> +#include <stdlib.h> + +#include "minimal_runtime.h" + +void print_and_exit(void) { +// CHECK-NOT: Stack overflow successful. +// OVERFLOW_SUCCESS: Stack overflow successful. + scs_fputs_stdout("Stack overflow successful.\n"); + exit(0); +} + +int scs_main(void) +{ + void *addrs[4]; + for (int i = 0; i < ITERATIONS; i++) + addrs[i] = &print_and_exit; + + scs_fputs_stdout("Returning.\n"); + + return 0; +} |