[compiler-rt] r239763 - Protection against stack-based memory corruption errors using SafeStack: compiler-rt runtime support library

Peter Collingbourne peter at pcc.me.uk
Tue Jun 16 12:00:00 PDT 2015


Anna,

I couldn't immediately see the cause of the problem so I've XFAILed the test
for now in r239841. I'll try to investigate more closely later.

Peter

On Tue, Jun 16, 2015 at 11:35:50AM -0700, Anna Zaks wrote:
> Very exciting to see this!  
> 
> The commit has caused one test failure on darwin:
> http://lab.llvm.org:8080/green/view/All/job/clang-stage1-cmake-RA_check/4796/console
> 
> Failing Tests (1):
>     SafeStack :: pthread.c
> 
> Will you be able to investigate?
> 
> Thanks!
> Anna.
> > On Jun 15, 2015, at 2:08 PM, Peter Collingbourne <peter at pcc.me.uk> wrote:
> > 
> > Author: pcc
> > Date: Mon Jun 15 16:08:47 2015
> > New Revision: 239763
> > 
> > URL: http://llvm.org/viewvc/llvm-project?rev=239763&view=rev
> > Log:
> > Protection against stack-based memory corruption errors using SafeStack: compiler-rt runtime support library
> > 
> > This patch adds runtime support for the Safe Stack protection to compiler-rt
> > (see http://reviews.llvm.org/D6094 for the detailed description of the
> > Safe Stack).
> > 
> > This patch is our implementation of the safe stack on top of compiler-rt. The
> > patch adds basic runtime support for the safe stack to compiler-rt that
> > manages unsafe stack allocation/deallocation for each thread.
> > 
> > Original patch by Volodymyr Kuznetsov and others at the Dependable Systems
> > Lab at EPFL; updates and upstreaming by myself.
> > 
> > Differential Revision: http://reviews.llvm.org/D6096
> > 
> > Added:
> >    compiler-rt/trunk/lib/safestack/
> >    compiler-rt/trunk/lib/safestack/CMakeLists.txt
> >    compiler-rt/trunk/lib/safestack/safestack.cc
> >    compiler-rt/trunk/test/safestack/
> >    compiler-rt/trunk/test/safestack/CMakeLists.txt
> >    compiler-rt/trunk/test/safestack/buffer-copy-vla.c
> >    compiler-rt/trunk/test/safestack/buffer-copy.c
> >    compiler-rt/trunk/test/safestack/init.c
> >    compiler-rt/trunk/test/safestack/lit.cfg
> >    compiler-rt/trunk/test/safestack/lit.site.cfg.in
> >    compiler-rt/trunk/test/safestack/lto.c
> >    compiler-rt/trunk/test/safestack/overflow.c
> >    compiler-rt/trunk/test/safestack/pthread-cleanup.c
> >    compiler-rt/trunk/test/safestack/pthread.c
> >    compiler-rt/trunk/test/safestack/utils.h
> > Modified:
> >    compiler-rt/trunk/CMakeLists.txt
> >    compiler-rt/trunk/cmake/config-ix.cmake
> >    compiler-rt/trunk/lib/CMakeLists.txt
> >    compiler-rt/trunk/test/CMakeLists.txt
> > 
> > Modified: compiler-rt/trunk/CMakeLists.txt
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/CMakeLists.txt?rev=239763&r1=239762&r2=239763&view=diff
> > ==============================================================================
> > --- compiler-rt/trunk/CMakeLists.txt (original)
> > +++ compiler-rt/trunk/CMakeLists.txt Mon Jun 15 16:08:47 2015
> > @@ -207,6 +207,7 @@ append_list_if(COMPILER_RT_HAS_FNO_EXCEP
> > append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
> > append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
> > append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
> > +append_list_if(COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG -fno-sanitize=safe-stack SANITIZER_COMMON_CFLAGS)
> > append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
> > append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
> > append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
> > 
> > Modified: compiler-rt/trunk/cmake/config-ix.cmake
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/cmake/config-ix.cmake?rev=239763&r1=239762&r2=239763&view=diff
> > ==============================================================================
> > --- compiler-rt/trunk/cmake/config-ix.cmake (original)
> > +++ compiler-rt/trunk/cmake/config-ix.cmake Mon Jun 15 16:08:47 2015
> > @@ -19,6 +19,7 @@ check_cxx_compiler_flag(-fno-exceptions
> > check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)
> > check_cxx_compiler_flag(-funwind-tables      COMPILER_RT_HAS_FUNWIND_TABLES_FLAG)
> > check_cxx_compiler_flag(-fno-stack-protector COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG)
> > +check_cxx_compiler_flag(-fno-sanitize=safe-stack COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG)
> > check_cxx_compiler_flag(-fvisibility=hidden  COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
> > check_cxx_compiler_flag(-fno-rtti            COMPILER_RT_HAS_FNO_RTTI_FLAG)
> > check_cxx_compiler_flag(-ffreestanding       COMPILER_RT_HAS_FFREESTANDING_FLAG)
> > @@ -256,6 +257,7 @@ filter_available_targets(PROFILE_SUPPORT
> > filter_available_targets(TSAN_SUPPORTED_ARCH x86_64 mips64 mips64el)
> > filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips
> >   mipsel mips64 mips64el powerpc64 powerpc64le)
> > +filter_available_targets(SAFESTACK_SUPPORTED_ARCH x86_64 i386 i686)
> > 
> > if(ANDROID)
> >   set(OS_NAME "Android")
> > @@ -334,3 +336,10 @@ endif()
> > if("${LLVM_NATIVE_ARCH}" STREQUAL "Mips")
> >   set(COMPILER_RT_HAS_MSSE3_FLAG FALSE)
> > endif()
> > +
> > +if (SAFESTACK_SUPPORTED_ARCH AND
> > +    OS_NAME MATCHES "Darwin|Linux|FreeBSD")
> > +  set(COMPILER_RT_HAS_SAFESTACK TRUE)
> > +else()
> > +  set(COMPILER_RT_HAS_SAFESTACK FALSE)
> > +endif()
> > 
> > Modified: compiler-rt/trunk/lib/CMakeLists.txt
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/CMakeLists.txt?rev=239763&r1=239762&r2=239763&view=diff
> > ==============================================================================
> > --- compiler-rt/trunk/lib/CMakeLists.txt (original)
> > +++ compiler-rt/trunk/lib/CMakeLists.txt Mon Jun 15 16:08:47 2015
> > @@ -34,3 +34,6 @@ if(COMPILER_RT_HAS_TSAN)
> >   add_subdirectory(tsan/dd)
> > endif()
> > 
> > +if(COMPILER_RT_HAS_SAFESTACK)
> > +  add_subdirectory(safestack)
> > +endif()
> > 
> > Added: compiler-rt/trunk/lib/safestack/CMakeLists.txt
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/safestack/CMakeLists.txt?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/lib/safestack/CMakeLists.txt (added)
> > +++ compiler-rt/trunk/lib/safestack/CMakeLists.txt Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,28 @@
> > +add_custom_target(safestack)
> > +
> > +set(SAFESTACK_SOURCES safestack.cc)
> > +
> > +include_directories(..)
> > +
> > +set(SAFESTACK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
> > +
> > +if(APPLE)
> > +  # Build universal binary on APPLE.
> > +  add_compiler_rt_osx_static_runtime(clang_rt.safestack_osx
> > +    ARCH ${SAFESTACK_SUPPORTED_ARCH}
> > +    SOURCES ${SAFESTACK_SOURCES}
> > +            $<TARGET_OBJECTS:RTInterception.osx>
> > +            $<TARGET_OBJECTS:RTSanitizerCommon.osx>
> > +    CFLAGS ${SAFESTACK_CFLAGS})
> > +  add_dependencies(safestack clang_rt.safestack_osx)
> > +else()
> > +  # Otherwise, build separate libraries for each target.
> > +  foreach(arch ${SAFESTACK_SUPPORTED_ARCH})
> > +    add_compiler_rt_runtime(clang_rt.safestack-${arch} ${arch} STATIC
> > +      SOURCES ${SAFESTACK_SOURCES}
> > +              $<TARGET_OBJECTS:RTInterception.${arch}>
> > +              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
> > +      CFLAGS ${SAFESTACK_CFLAGS})
> > +    add_dependencies(safestack clang_rt.safestack-${arch})
> > +  endforeach()
> > +endif()
> > 
> > Added: compiler-rt/trunk/lib/safestack/safestack.cc
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/safestack/safestack.cc?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/lib/safestack/safestack.cc (added)
> > +++ compiler-rt/trunk/lib/safestack/safestack.cc Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,236 @@
> > +//===-- safestack.cc ------------------------------------------------------===//
> > +//
> > +//                     The LLVM Compiler Infrastructure
> > +//
> > +// This file is distributed under the University of Illinois Open Source
> > +// License. See LICENSE.TXT for details.
> > +//
> > +//===----------------------------------------------------------------------===//
> > +//
> > +// This file implements the runtime support for the safe stack protection
> > +// mechanism. The runtime manages allocation/deallocation of the unsafe stack
> > +// for the main thread, as well as all pthreads that are created/destroyed
> > +// during program execution.
> > +//
> > +//===----------------------------------------------------------------------===//
> > +
> > +#include <limits.h>
> > +#include <pthread.h>
> > +#include <stddef.h>
> > +#include <sys/resource.h>
> > +#include <sys/user.h>
> > +
> > +#include "interception/interception.h"
> > +#include "sanitizer_common/sanitizer_common.h"
> > +
> > +// TODO: The runtime library does not currently protect the safe stack. The
> > +// protection of the (safe) stack can be provided by two alternative features
> > +// that requires C library support:
> > +//
> > +// 1) Protection via hardware segmentation on x32 architectures: the (safe)
> > +// stack segment (implicitly accessed via the %ss segment register) can be
> > +// separated from the data segment (implicitly accessed via the %ds segment
> > +// register). Dereferencing a pointer to the safe segment would result in a
> > +// segmentation fault.
> > +//
> > +// 2) Protection via information hiding on 64 bit architectures: the location of
> > +// the safe stack can be randomized through secure mechanisms, and the leakage
> > +// of the stack pointer can be prevented. Currently, libc can leak the stack
> > +// pointer in several ways (e.g. in longjmp, signal handling, user-level context
> > +// switching related functions, etc.). These can be fixed in libc and in other
> > +// low-level libraries, by either eliminating the escaping/dumping of the stack
> > +// pointer (i.e., %rsp) when that's possible, or by using encryption/PTR_MANGLE
> > +// (XOR-ing the dumped stack pointer with another secret we control and protect
> > +// better). (This is already done for setjmp in glibc.) Furthermore, a static
> > +// machine code level verifier can be ran after code generation to make sure
> > +// that the stack pointer is never written to memory, or if it is, its written
> > +// on the safe stack.
> > +//
> > +// Finally, while the Unsafe Stack pointer is currently stored in a thread local
> > +// variable, with libc support it could be stored in the TCB (thread control
> > +// block) as well, eliminating another level of indirection. Alternatively,
> > +// dedicating a separate register for storing it would also be possible.
> > +
> > +/// Minimum stack alignment for the unsafe stack.
> > +const unsigned kStackAlign = 16;
> > +
> > +/// Default size of the unsafe stack. This value is only used if the stack
> > +/// size rlimit is set to infinity.
> > +const unsigned kDefaultUnsafeStackSize = 0x2800000;
> > +
> > +// TODO: To make accessing the unsafe stack pointer faster, we plan to
> > +// eventually store it directly in the thread control block data structure on
> > +// platforms where this structure is pointed to by %fs or %gs. This is exactly
> > +// the same mechanism as currently being used by the traditional stack
> > +// protector pass to store the stack guard (see getStackCookieLocation()
> > +// function above). Doing so requires changing the tcbhead_t struct in glibc
> > +// on Linux and tcb struct in libc on FreeBSD.
> > +//
> > +// For now, store it in a thread-local variable.
> > +extern "C" {
> > +__attribute__((visibility(
> > +    "default"))) __thread void *__safestack_unsafe_stack_ptr = nullptr;
> > +}
> > +
> > +// Per-thread unsafe stack information. It's not frequently accessed, so there
> > +// it can be kept out of the tcb in normal thread-local variables.
> > +static __thread void *unsafe_stack_start = nullptr;
> > +static __thread size_t unsafe_stack_size = 0;
> > +static __thread size_t unsafe_stack_guard = 0;
> > +
> > +static inline void *unsafe_stack_alloc(size_t size, size_t guard) {
> > +  CHECK_GE(size + guard, size);
> > +  void *addr = MmapOrDie(size + guard, "unsafe_stack_alloc");
> > +  MprotectNoAccess((uptr)addr, (uptr)guard);
> > +  return (char *)addr + guard;
> > +}
> > +
> > +static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
> > +  CHECK_GE((char *)start + size, (char *)start);
> > +  CHECK_GE((char *)start + guard, (char *)start);
> > +  void *stack_ptr = (char *)start + size;
> > +  CHECK_EQ((((size_t)stack_ptr) & (kStackAlign - 1)), 0);
> > +
> > +  __safestack_unsafe_stack_ptr = stack_ptr;
> > +  unsafe_stack_start = start;
> > +  unsafe_stack_size = size;
> > +  unsafe_stack_guard = guard;
> > +}
> > +
> > +static void unsafe_stack_free() {
> > +  if (unsafe_stack_start) {
> > +    UnmapOrDie((char *)unsafe_stack_start - unsafe_stack_guard,
> > +               unsafe_stack_size + unsafe_stack_guard);
> > +  }
> > +  unsafe_stack_start = nullptr;
> > +}
> > +
> > +/// Thread data for the cleanup handler
> > +static pthread_key_t thread_cleanup_key;
> > +
> > +/// Safe stack per-thread information passed to the thread_start function
> > +struct tinfo {
> > +  void *(*start_routine)(void *);
> > +  void *start_routine_arg;
> > +
> > +  void *unsafe_stack_start;
> > +  size_t unsafe_stack_size;
> > +  size_t unsafe_stack_guard;
> > +};
> > +
> > +/// Wrap the thread function in order to deallocate the unsafe stack when the
> > +/// thread terminates by returning from its main function.
> > +static void *thread_start(void *arg) {
> > +  struct tinfo *tinfo = (struct tinfo *)arg;
> > +
> > +  void *(*start_routine)(void *) = tinfo->start_routine;
> > +  void *start_routine_arg = tinfo->start_routine_arg;
> > +
> > +  // Setup the unsafe stack; this will destroy tinfo content
> > +  unsafe_stack_setup(tinfo->unsafe_stack_start, tinfo->unsafe_stack_size,
> > +                     tinfo->unsafe_stack_guard);
> > +
> > +  // Make sure out thread-specific destructor will be called
> > +  // FIXME: we can do this only any other specific key is set by
> > +  // intercepting the pthread_setspecific function itself
> > +  pthread_setspecific(thread_cleanup_key, (void *)1);
> > +
> > +  return start_routine(start_routine_arg);
> > +}
> > +
> > +/// Thread-specific data destructor
> > +static void thread_cleanup_handler(void *_iter) {
> > +  // We want to free the unsafe stack only after all other destructors
> > +  // have already run. We force this function to be called multiple times.
> > +  // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
> > +  // times might still end up executing after the unsafe stack is deallocated.
> > +  size_t iter = (size_t)_iter;
> > +  if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
> > +    pthread_setspecific(thread_cleanup_key, (void *)(iter + 1));
> > +  } else {
> > +    // This is the last iteration
> > +    unsafe_stack_free();
> > +  }
> > +}
> > +
> > +/// Intercept thread creation operation to allocate and setup the unsafe stack
> > +INTERCEPTOR(int, pthread_create, pthread_t *thread,
> > +            const pthread_attr_t *attr,
> > +            void *(*start_routine)(void*), void *arg) {
> > +
> > +  size_t size = 0;
> > +  size_t guard = 0;
> > +
> > +  if (attr != NULL) {
> > +    pthread_attr_getstacksize(attr, &size);
> > +    pthread_attr_getguardsize(attr, &guard);
> > +  } else {
> > +    // get pthread default stack size
> > +    pthread_attr_t tmpattr;
> > +    pthread_attr_init(&tmpattr);
> > +    pthread_attr_getstacksize(&tmpattr, &size);
> > +    pthread_attr_getguardsize(&tmpattr, &guard);
> > +    pthread_attr_destroy(&tmpattr);
> > +  }
> > +
> > +  CHECK_NE(size, 0);
> > +  CHECK_EQ((size & (kStackAlign - 1)), 0);
> > +  CHECK_EQ((guard & (PAGE_SIZE - 1)), 0);
> > +
> > +  void *addr = unsafe_stack_alloc(size, guard);
> > +  struct tinfo *tinfo =
> > +      (struct tinfo *)(((char *)addr) + size - sizeof(struct tinfo));
> > +  tinfo->start_routine = start_routine;
> > +  tinfo->start_routine_arg = arg;
> > +  tinfo->unsafe_stack_start = addr;
> > +  tinfo->unsafe_stack_size = size;
> > +  tinfo->unsafe_stack_guard = guard;
> > +
> > +  return REAL(pthread_create)(thread, attr, thread_start, tinfo);
> > +}
> > +
> > +extern "C" __attribute__((visibility("default")))
> > +#if !SANITIZER_CAN_USE_PREINIT_ARRAY
> > +// On ELF platforms, the constructor is invoked using .preinit_array (see below)
> > +__attribute__((constructor(0)))
> > +#endif
> > +void __safestack_init() {
> > +  // Determine the stack size for the main thread.
> > +  size_t size = kDefaultUnsafeStackSize;
> > +  size_t guard = 4096;
> > +
> > +  struct rlimit limit;
> > +  if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur != RLIM_INFINITY)
> > +    size = limit.rlim_cur;
> > +
> > +  // Allocate unsafe stack for main thread
> > +  void *addr = unsafe_stack_alloc(size, guard);
> > +
> > +  unsafe_stack_setup(addr, size, guard);
> > +
> > +  // Initialize pthread interceptors for thread allocation
> > +  INTERCEPT_FUNCTION(pthread_create);
> > +
> > +  // Setup the cleanup handler
> > +  pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
> > +}
> > +
> > +#if SANITIZER_CAN_USE_PREINIT_ARRAY
> > +// On ELF platforms, run safestack initialization before any other constructors.
> > +// On other platforms we use the constructor attribute to arrange to run our
> > +// initialization early.
> > +extern "C" {
> > +__attribute__((section(".preinit_array"),
> > +               used)) void (*__safestack_preinit)(void) = __safestack_init;
> > +}
> > +#endif
> > +
> > +extern "C"
> > +    __attribute__((visibility("default"))) void *__get_unsafe_stack_start() {
> > +  return unsafe_stack_start;
> > +}
> > +
> > +extern "C"
> > +    __attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() {
> > +  return __safestack_unsafe_stack_ptr;
> > +}
> > 
> > Modified: compiler-rt/trunk/test/CMakeLists.txt
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/CMakeLists.txt?rev=239763&r1=239762&r2=239763&view=diff
> > ==============================================================================
> > --- compiler-rt/trunk/test/CMakeLists.txt (original)
> > +++ compiler-rt/trunk/test/CMakeLists.txt Mon Jun 15 16:08:47 2015
> > @@ -58,6 +58,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
> >     add_subdirectory(ubsan)
> >   endif()
> >   add_subdirectory(cfi)
> > +  if(COMPILER_RT_HAS_SAFESTACK)
> > +    add_subdirectory(safestack)
> > +  endif()
> > endif()
> > 
> > if(COMPILER_RT_STANDALONE_BUILD)
> > 
> > Added: compiler-rt/trunk/test/safestack/CMakeLists.txt
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/CMakeLists.txt?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/CMakeLists.txt (added)
> > +++ compiler-rt/trunk/test/safestack/CMakeLists.txt Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,29 @@
> > +set(SAFESTACK_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
> > +set(SAFESTACK_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
> > +
> > +set(SAFESTACK_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
> > +if(NOT COMPILER_RT_STANDALONE_BUILD)
> > +  list(APPEND SAFESTACK_TEST_DEPS safestack)
> > +
> > +  # Some tests require LTO, so add a dependency on the relevant LTO plugin.
> > +  if(LLVM_ENABLE_PIC AND LLVM_BINUTILS_INCDIR)
> > +    list(APPEND SAFESTACK_TEST_DEPS
> > +      LLVMgold
> > +    )
> > +  endif()
> > +  if(APPLE)
> > +    list(APPEND SAFESTACK_TEST_DEPS
> > +      LTO
> > +    )
> > +  endif()
> > +endif()
> > +
> > +configure_lit_site_cfg(
> > +  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
> > +  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
> > +  )
> > +
> > +add_lit_testsuite(check-safestack "Running the SafeStack tests"
> > +  ${CMAKE_CURRENT_BINARY_DIR}
> > +  DEPENDS ${SAFESTACK_TEST_DEPS})
> > +set_target_properties(check-safestack PROPERTIES FOLDER "SafeStack tests")
> > 
> > Added: compiler-rt/trunk/test/safestack/buffer-copy-vla.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/buffer-copy-vla.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/buffer-copy-vla.c (added)
> > +++ compiler-rt/trunk/test/safestack/buffer-copy-vla.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,26 @@
> > +// RUN: %clang_safestack %s -o %t
> > +// RUN: %run %t
> > +
> > +#include "utils.h"
> > +
> > +// Test that loads/stores work correctly for VLAs on the unsafe stack.
> > +
> > +int main(int argc, char **argv)
> > +{
> > +  int i = 128;
> > +  break_optimization(&i);
> > +  char buffer[i];
> > +
> > +  // check that we can write to a buffer
> > +  for (i = 0; argv[0][i] && i < sizeof (buffer) - 1; ++i)
> > +    buffer[i] = argv[0][i];
> > +  buffer[i] = '\0';
> > +
> > +  break_optimization(buffer);
> > +
> > +  // check that we can read from a buffer
> > +  for (i = 0; argv[0][i] && i < sizeof (buffer) - 1; ++i)
> > +    if (buffer[i] != argv[0][i])
> > +      return 1;
> > +  return 0;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/buffer-copy.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/buffer-copy.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/buffer-copy.c (added)
> > +++ compiler-rt/trunk/test/safestack/buffer-copy.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,25 @@
> > +// RUN: %clang_safestack %s -o %t
> > +// RUN: %run %t
> > +
> > +#include "utils.h"
> > +
> > +// Test that loads/stores work correctly for variables on the unsafe stack.
> > +
> > +int main(int argc, char **argv)
> > +{
> > +  int i;
> > +  char buffer[128];
> > +
> > +  // check that we can write to a buffer
> > +  for (i = 0; argv[0][i] && i < sizeof (buffer) - 1; ++i)
> > +    buffer[i] = argv[0][i];
> > +  buffer[i] = '\0';
> > +
> > +  break_optimization(buffer);
> > +
> > +  // check that we can read from a buffer
> > +  for (i = 0; argv[0][i] && i < sizeof (buffer) - 1; ++i)
> > +    if (buffer[i] != argv[0][i])
> > +      return 1;
> > +  return 0;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/init.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/init.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/init.c (added)
> > +++ compiler-rt/trunk/test/safestack/init.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,9 @@
> > +// RUN: %clang_safestack %s -o %t
> > +// RUN: %run %t
> > +
> > +// Basic smoke test for the runtime library.
> > +
> > +int main(int argc, char **argv)
> > +{
> > +  return 0;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/lit.cfg
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/lit.cfg?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/lit.cfg (added)
> > +++ compiler-rt/trunk/test/safestack/lit.cfg Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,24 @@
> > +# -*- Python -*-
> > +
> > +import os
> > +
> > +# Setup config name.
> > +config.name = 'SafeStack'
> > +
> > +# 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_nosafestack ", config.clang + " -O0 -fno-sanitize=safe-stack ") )
> > +config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsanitize=safe-stack ") )
> > +
> > +if config.lto_supported:
> > +  config.available_features.add('lto')
> > +  config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=safe-stack '])))
> > +
> > +# SafeStack tests are currently supported on Linux, FreeBSD and Darwin only.
> > +if config.host_os not in ['Linux', 'FreeBSD', 'Darwin']:
> > +   config.unsupported = True
> > 
> > Added: compiler-rt/trunk/test/safestack/lit.site.cfg.in
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/lit.site.cfg.in?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/lit.site.cfg.in (added)
> > +++ compiler-rt/trunk/test/safestack/lit.site.cfg.in Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,8 @@
> > +## Autogenerated by LLVM/Clang configuration.
> > +# Do not edit!
> > +
> > +# 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, "@SAFESTACK_LIT_SOURCE_DIR@/lit.cfg")
> > 
> > Added: compiler-rt/trunk/test/safestack/lto.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/lto.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/lto.c (added)
> > +++ compiler-rt/trunk/test/safestack/lto.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,12 @@
> > +// REQUIRES: lto
> > +
> > +// RUN: %clang_lto_safestack %s -o %t
> > +// RUN: %run %t
> > +
> > +// Test that safe stack works with LTO.
> > +
> > +int main() {
> > +  char c[] = "hello world";
> > +  puts(c);
> > +  return 0;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/overflow.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/overflow.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/overflow.c (added)
> > +++ compiler-rt/trunk/test/safestack/overflow.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,23 @@
> > +// RUN: %clang_safestack %s -o %t
> > +// RUN: %run %t
> > +
> > +// RUN: %clang_nosafestack -fno-stack-protector %s -o %t
> > +// RUN: not %run %t
> > +
> > +// Test that buffer overflows on the unsafe stack do not affect variables on the
> > +// safe stack.
> > +
> > +__attribute__((noinline))
> > +void fct(volatile int *buffer)
> > +{
> > +  memset(buffer - 1, 0, 7 * sizeof(int));
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +  int value1 = 42;
> > +  int buffer[5];
> > +  int value2 = 42;
> > +  fct(buffer);
> > +  return value1 != 42 || value2 != 42;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/pthread-cleanup.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/pthread-cleanup.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/pthread-cleanup.c (added)
> > +++ compiler-rt/trunk/test/safestack/pthread-cleanup.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,31 @@
> > +// RUN: %clang_safestack %s -pthread -o %t
> > +// RUN: not --crash %run %t
> > +
> > +// Test that unsafe stacks are deallocated correctly on thread exit.
> > +
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <pthread.h>
> > +
> > +enum { kBufferSize = (1 << 15) };
> > +
> > +void *t1_start(void *ptr)
> > +{
> > +  char buffer[kBufferSize];
> > +  return buffer;
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +  pthread_t t1;
> > +  char *buffer = NULL;
> > +
> > +  if (pthread_create(&t1, NULL, t1_start, NULL))
> > +    abort();
> > +  if (pthread_join(t1, &buffer))
> > +    abort();
> > +
> > +  // should segfault here
> > +  memset(buffer, 0, kBufferSize);
> > +  return 0;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/pthread.c
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/pthread.c?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/pthread.c (added)
> > +++ compiler-rt/trunk/test/safestack/pthread.c Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,40 @@
> > +// RUN: %clang_safestack %s -pthread -o %t
> > +// RUN: %run %t
> > +
> > +// Test that pthreads receive their own unsafe stack.
> > +
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <pthread.h>
> > +#include "utils.h"
> > +
> > +static int ptr_test = 42;
> > +
> > +void *t1_start(void *ptr)
> > +{
> > +  if (ptr != &ptr_test)
> > +    abort();
> > +
> > +  // safe stack
> > +  int val = ptr_test * 5;
> > +
> > +  // unsafe stack
> > +  char buffer[8096]; // two pages
> > +  memset(buffer, val, sizeof (buffer));
> > +  break_optimization(buffer);
> > +
> > +  return ptr;
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +  pthread_t t1;
> > +  void *ptr = NULL;
> > +  if (pthread_create(&t1, NULL, t1_start, &ptr_test))
> > +    abort();
> > +  if (pthread_join(t1, &ptr))
> > +    abort();
> > +  if (ptr != &ptr_test)
> > +    abort();
> > +  return 0;
> > +}
> > 
> > Added: compiler-rt/trunk/test/safestack/utils.h
> > URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/safestack/utils.h?rev=239763&view=auto
> > ==============================================================================
> > --- compiler-rt/trunk/test/safestack/utils.h (added)
> > +++ compiler-rt/trunk/test/safestack/utils.h Mon Jun 15 16:08:47 2015
> > @@ -0,0 +1,8 @@
> > +#ifndef UTILS_H
> > +#define UTILS_H
> > +
> > +static inline void break_optimization(void *arg) {
> > +  __asm__ __volatile__("" : : "r" (arg) : "memory");
> > +}
> > +
> > +#endif
> > 
> > 
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> 

-- 
Peter



More information about the llvm-commits mailing list