Added tests for the safestack runtime support library.
http://reviews.llvm.org/D6096
Files:
CMakeLists.txt
cmake/config-ix.cmake
include/CMakeLists.txt
include/safestack_interface.h
lib/CMakeLists.txt
lib/Makefile.mk
lib/safestack/CMakeLists.txt
lib/safestack/Makefile.mk
lib/safestack/safestack.cc
make/platform/clang_darwin.mk
make/platform/clang_linux.mk
test/CMakeLists.txt
test/safestack/CMakeLists.txt
test/safestack/check-buffer-copy.c
test/safestack/check-init.c
test/safestack/check-overflow.c
test/safestack/check-pthread-cleanup.c
test/safestack/check-pthread.c
test/safestack/lit.cfg
test/safestack/lit.site.cfg.in
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -239,6 +239,7 @@
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_SAFE_STACK_FLAG -fno-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)
Index: cmake/config-ix.cmake
===================================================================
--- cmake/config-ix.cmake
+++ cmake/config-ix.cmake
@@ -10,6 +10,7 @@
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-safe-stack COMPILER_RT_HAS_FNO_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)
@@ -182,6 +183,7 @@
filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 i686 arm mips mips64 mipsel mips64el aarch64)
filter_available_targets(TSAN_SUPPORTED_ARCH x86_64)
filter_available_targets(UBSAN_SUPPORTED_ARCH x86_64 i386 i686 arm aarch64 mips mipsel)
+filter_available_targets(SAFESTACK_SUPPORTED_ARCH x86_64 i386 i686)
if(ANDROID)
set(OS_NAME "Android")
@@ -254,3 +256,9 @@
set(COMPILER_RT_HAS_UBSAN 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()
Index: include/CMakeLists.txt
===================================================================
--- include/CMakeLists.txt
+++ include/CMakeLists.txt
@@ -6,7 +6,8 @@
sanitizer/linux_syscall_hooks.h
sanitizer/lsan_interface.h
sanitizer/msan_interface.h
- sanitizer/tsan_interface_atomic.h)
+ sanitizer/tsan_interface_atomic.h
+ safestack_interface.h)
set(output_dir ${COMPILER_RT_OUTPUT_DIR}/include)
Index: include/safestack_interface.h
===================================================================
--- /dev/null
+++ include/safestack_interface.h
@@ -0,0 +1,20 @@
+#ifndef SAFESTACK_INTERFACE_H
+#define SAFESTACK_INTERFACE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *__safestack_get_unsafe_stack_start();
+void *__safestack_get_unsafe_stack_ptr();
+size_t __safestack_get_unsafe_stack_size();
+
+void *__safestack_get_safe_stack_ptr();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SAFESTACK_INTERFACE_H
Index: lib/CMakeLists.txt
===================================================================
--- lib/CMakeLists.txt
+++ lib/CMakeLists.txt
@@ -41,3 +41,4 @@
add_subdirectory(ubsan)
endif()
+add_subdirectory(safestack)
Index: lib/Makefile.mk
===================================================================
--- lib/Makefile.mk
+++ lib/Makefile.mk
@@ -20,3 +20,4 @@
SubDirs += sanitizer_common
SubDirs += tsan
SubDirs += ubsan
+SubDirs += safestack
Index: lib/safestack/CMakeLists.txt
===================================================================
--- /dev/null
+++ lib/safestack/CMakeLists.txt
@@ -0,0 +1,26 @@
+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>
+ 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}>
+ CFLAGS ${SAFESTACK_CFLAGS})
+ add_dependencies(safestack clang_rt.safestack-${arch})
+ endforeach()
+endif()
Index: lib/safestack/Makefile.mk
===================================================================
--- /dev/null
+++ lib/safestack/Makefile.mk
@@ -0,0 +1,23 @@
+#===- lib/safestack/Makefile.mk ------------------------------*- Makefile -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+ModuleName := safestack
+SubDirs :=
+
+Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+ObjNames := $(Sources:%.cc=%.o)
+
+Implementation := Generic
+
+# FIXME: use automatic dependencies?
+Dependencies := $(wildcard $(Dir)/*.h)
+Dependencies += $(wildcard $(Dir)/../interception/*.h)
+
+# Define a convenience variable for all the safestack functions.
+SafeStackFunctions := $(Sources:%.cc=%)
Index: lib/safestack/safestack.cc
===================================================================
--- /dev/null
+++ lib/safestack/safestack.cc
@@ -0,0 +1,358 @@
+//===-- safestack.cc --------------------------------------------*- C++ -*-===//
+//
+// 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 threads that are
+// created/destroyed during program execution.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#if defined(__linux__)
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+
+/// Minimum stack alignment for the unsafe stack.
+/// FIXME: is this in some header?
+#define STACK_ALIGN 16
+
+/// Default size of the unsafe stack. This value is only used if the stack
+/// size rlimit is set to infinity.
+#define DEFAULT_UNSAFE_STACK_SIZE 0x2800000
+
+
+// define MAP_STACK if undefined, this flag is used as a hint
+#ifndef MAP_STACK
+# define MAP_STACK 0
+#endif
+
+// define MAP_GROWSDOWN if undefined, this flag is used as a hint
+#ifndef MAP_GROWSDOWN
+# define MAP_GROWSDOWN 0
+#endif
+
+// define mmap wrapper, on Apple you can't override the mmap symbol
+// but on Linux it is possible, so we use syscall to ensure calling
+// kernel's mmap
+#if defined(__APPLE__)
+# define safestack_mmap(Args...) mmap(Args)
+# define safestack_munmap(Args...) munmap(Args)
+#else
+# define safestack_mmap(Args...) (void *)syscall(SYS_mmap, Args)
+# define safestack_munmap(Args...) (int)syscall(SYS_munmap, Args)
+#endif
+
+#include "interception/interception.h"
+
+namespace __llvm__safestack {
+
+// We don't know whether pthread is linked in or not, so we resolve
+// all symbols from pthread that we use dynamically
+#define __DECLARE_WRAPPER(fn) __typeof__(fn)* __d_ ## fn = NULL;
+
+__DECLARE_WRAPPER(pthread_attr_init)
+__DECLARE_WRAPPER(pthread_attr_destroy)
+__DECLARE_WRAPPER(pthread_attr_getstacksize)
+__DECLARE_WRAPPER(pthread_attr_getguardsize)
+__DECLARE_WRAPPER(pthread_key_create)
+__DECLARE_WRAPPER(pthread_setspecific)
+
+// The unsafe stack pointer is stored in the TCB structure on these platforms
+#if defined(__i386__)
+# define MOVPTR "movl"
+# ifdef __pic__
+# define IMM_MODE "nr"
+# else
+# define IMM_MODE "ir"
+# endif
+#elif defined(__x86_64__)
+# define MOVPTR "movq"
+# define IMM_MODE "nr"
+#endif
+
+#if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
+
+ /* On Darwin, we store the unsafe stack pointer in one of the
+ * thread-specific data slots that are reserved for system libraries.
+ * Such data slots are directly accessible through the %gs segment, and
+ * are described in detail in pthreads/pthread_machdep.h in Darwin Libc.
+ * As of Libc-825, slots 0 - 255 are reserved, but only slots 0 - 119
+ * are actually used. We use slot 192, which is accessible as
+ * %gs:(192 * sizeof(void*))
+ */
+
+# define __THREAD_GETMEM_L(slot) \
+ __extension__ ({ unsigned long __v; \
+ asm volatile (MOVPTR " %%gs:%P1,%q0" : "=r" (__v) \
+ : "i" ((slot) * sizeof(void*))); __v; })
+
+# define __THREAD_SETMEM_L(slot, value) \
+ asm volatile (MOVPTR " %q0,%%gs:%P1" : \
+ : IMM_MODE ((unsigned long) (value)), \
+ "i" ((slot) * sizeof(void*)))
+
+// The following locations are platform-specific
+# define __GET_UNSAFE_STACK_PTR() (void*) __THREAD_GETMEM_L(192)
+# define __SET_UNSAFE_STACK_PTR(value) __THREAD_SETMEM_L(192, value)
+
+#else
+
+ /* 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.
+ */
+
+// The unsafe stack is stored in a thread-local variable on all other platforms
+extern "C" {
+ __attribute__((visibility ("default")))
+ __thread void *__llvm__unsafe_stack_ptr = 0;
+}
+
+# define __GET_UNSAFE_STACK_PTR() __llvm__unsafe_stack_ptr
+# define __SET_UNSAFE_STACK_PTR(value) __llvm__unsafe_stack_ptr = (value)
+
+#endif
+
+// 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 = 0;
+static __thread size_t unsafe_stack_size = 0;
+static __thread size_t unsafe_stack_guard = 0;
+
+# define __GET_UNSAFE_STACK_START() unsafe_stack_start
+# define __SET_UNSAFE_STACK_START(value) unsafe_stack_start = (value)
+
+# define __GET_UNSAFE_STACK_SIZE() unsafe_stack_size
+# define __SET_UNSAFE_STACK_SIZE(value) unsafe_stack_size = (value)
+
+# define __GET_UNSAFE_STACK_GUARD() unsafe_stack_guard
+# define __SET_UNSAFE_STACK_GUARD(value) unsafe_stack_guard = (value)
+
+static inline void *unsafe_stack_alloc(size_t size, size_t guard) {
+ // We need the mmap system call without any LD_PRELOAD overrides
+ // (such overrides might crash is they use the unsafe stack themselves)
+ void *addr = safestack_mmap(NULL, size + guard, PROT_WRITE | PROT_READ,
+ MAP_PRIVATE | MAP_ANON | MAP_STACK | MAP_GROWSDOWN, -1, 0);
+
+ if (addr == MAP_FAILED)
+ return nullptr;
+
+ mprotect(addr, guard, PROT_NONE);
+ return (char*) addr + guard;
+}
+
+static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
+ void* stack_ptr = (char*) start + size;
+ assert((((size_t)stack_ptr) & (STACK_ALIGN-1)) == 0);
+
+ __SET_UNSAFE_STACK_PTR(stack_ptr);
+ __SET_UNSAFE_STACK_START(start);
+ __SET_UNSAFE_STACK_SIZE(size);
+ __SET_UNSAFE_STACK_GUARD(guard);
+}
+
+static void unsafe_stack_free() {
+ if (__GET_UNSAFE_STACK_START()) {
+ // We need the munmap system call without any LD_PRELOAD overrides
+ // (such overrides might crash is they use the unsafe stack themselves)
+ (void)safestack_munmap(
+ (char*) __GET_UNSAFE_STACK_START() - __GET_UNSAFE_STACK_GUARD(),
+ __GET_UNSAFE_STACK_SIZE() + __GET_UNSAFE_STACK_GUARD());
+ }
+ __SET_UNSAFE_STACK_START(0);
+}
+
+/// Thread data for the cleanup handler
+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
+ // intersepting the pthread_setspecific function itself
+ __d_pthread_setspecific(thread_cleanup_key, (void*) 1);
+
+ // Start the original thread rutine
+ return start_routine(start_routine_arg);
+}
+
+/// 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) {
+ __d_pthread_attr_getstacksize(attr, &size);
+ __d_pthread_attr_getguardsize(attr, &guard);
+ } else {
+ // get pthread default stack size
+ pthread_attr_t tmpattr;
+ __d_pthread_attr_init(&tmpattr);
+ __d_pthread_attr_getstacksize(&tmpattr, &size);
+ __d_pthread_attr_getguardsize(&tmpattr, &guard);
+ __d_pthread_attr_destroy(&tmpattr);
+ }
+
+ assert(size != 0);
+ assert((size & (STACK_ALIGN-1)) == 0);
+ assert((guard & (PAGE_SIZE-1)) == 0);
+
+ void *addr = unsafe_stack_alloc(size, guard);
+ if (!addr) {
+ // failed to allocate the unsafe stack
+ errno = EAGAIN;
+ return -1;
+ }
+ 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);
+}
+
+/// Thread-specific data destructor
+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,
+ // so such descructors must have __attribute__((no_safe_stack)).
+ size_t iter = (size_t) _iter;
+ if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
+ __d_pthread_setspecific(thread_cleanup_key, (void*) (iter + 1));
+ } else {
+ // This is the last iteration
+ unsafe_stack_free();
+ }
+}
+
+extern "C"
+__attribute__((visibility ("default")))
+#ifndef __ELF__
+// On ELF platforms, the constructor is invoked using .preinit_array (see below)
+__attribute__((constructor(0)))
+#endif
+void __llvm__safestack_init() {
+ static int initialized = 0;
+
+ if (initialized)
+ return;
+
+ initialized = 1;
+
+ // Determine the stack size for the main thread.
+ size_t size = DEFAULT_UNSAFE_STACK_SIZE;
+ 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);
+ if (!addr)
+ // Failed to allocate the unsafe stack.
+ abort();
+
+ unsafe_stack_setup(addr, size, guard);
+
+ // Initialize pthread interceptors for thread allocation
+ INTERCEPT_FUNCTION(pthread_create);
+
+ #define __FIND_FUNCTION(fn) \
+ __d_ ## fn = __extension__ (__typeof__(__d_ ## fn)) dlsym(RTLD_DEFAULT, #fn);
+
+ // Find pthread functions that we need
+ __FIND_FUNCTION(pthread_attr_init)
+ __FIND_FUNCTION(pthread_attr_destroy)
+ __FIND_FUNCTION(pthread_attr_getstacksize)
+ __FIND_FUNCTION(pthread_attr_getguardsize)
+ __FIND_FUNCTION(pthread_key_create)
+ __FIND_FUNCTION(pthread_setspecific)
+
+ if (__d_pthread_key_create != NULL) {
+ // We're using pthreads, setup the cleanup handler
+ __d_pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
+ }
+}
+
+#ifdef __ELF__
+// Run safestack initialization before any other constructors.
+// FIXME: can we do something similar on non-ELF platforms, e.g., on Mac?
+extern "C" {
+__attribute__((section(".preinit_array"), used))
+void (*__llvm__safestack_preinit)(void) = __llvm__safestack_init;
+}
+#endif
+
+extern "C"
+__attribute__((visibility ("default")))
+void *__safestack_get_unsafe_stack_start() {
+ return __GET_UNSAFE_STACK_START();
+}
+
+extern "C"
+__attribute__((visibility ("default")))
+void *__safestack_get_unsafe_stack_ptr() {
+ return __GET_UNSAFE_STACK_PTR();
+}
+
+extern "C"
+__attribute__((visibility ("default")))
+__attribute__((noinline)) // required for __builtin_frame_address(0) to work
+void *__safestack_get_safe_stack_ptr() {
+ return (char*) __builtin_frame_address(0) + 2*sizeof(void*);
+}
+
+} // namespace __llvm__safestack
Index: make/platform/clang_darwin.mk
===================================================================
--- make/platform/clang_darwin.mk
+++ make/platform/clang_darwin.mk
@@ -106,6 +106,10 @@
Configs += ubsan_osx
UniversalArchs.ubsan_osx := $(call CheckArches,i386 x86_64 x86_64h,ubsan_osx)
+# Configurations which define the safestack support functions.
+Configs += safestack_osx
+UniversalArchs.safestack_osx = $(call CheckArches,i386 x86_64 x86_64h,safestack_osx)
+
# Darwin 10.6 has a bug in cctools that makes it unable to use ranlib on our ARM
# object files. If we are on that platform, strip out all ARM archs. We still
# build the libraries themselves so that Clang can find them where it expects
@@ -170,6 +174,10 @@
CFLAGS.ubsan_osx := $(CFLAGS) -mmacosx-version-min=10.6 -fno-builtin
+CFLAGS.safestack_osx := \
+ $(CFLAGS) -fno-rtti -fno-exceptions -fno-builtin \
+ -fno-stack-protector -fno-safe-stack
+
CFLAGS.ios.i386 := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
CFLAGS.ios.x86_64 := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
CFLAGS.ios.x86_64h := $(CFLAGS) $(IOSSIM_DEPLOYMENT_ARGS)
@@ -244,6 +252,8 @@
FUNCTIONS.ubsan_osx := $(UbsanFunctions) $(UbsanCXXFunctions) \
$(SanitizerCommonFunctions)
+FUNCTIONS.safestack_osx := $(SafeStackFunctions) $(InterceptionFunctions)
+
CCKEXT_COMMON_FUNCTIONS := \
absvdi2 \
absvsi2 \
Index: make/platform/clang_linux.mk
===================================================================
--- make/platform/clang_linux.mk
+++ make/platform/clang_linux.mk
@@ -50,21 +50,22 @@
# Build runtime libraries for i386.
ifeq ($(call contains,$(SupportedArches),i386),true)
Configs += builtins-i386 profile-i386 san-i386 asan-i386 asan_cxx-i386 \
- ubsan-i386 ubsan_cxx-i386
+ ubsan-i386 ubsan_cxx-i386 safestack-i386
Arch.builtins-i386 := i386
Arch.profile-i386 := i386
Arch.san-i386 := i386
Arch.asan-i386 := i386
Arch.asan_cxx-i386 := i386
Arch.ubsan-i386 := i386
Arch.ubsan_cxx-i386 := i386
+Arch.safestack-i386 := i386
endif
# Build runtime libraries for x86_64.
ifeq ($(call contains,$(SupportedArches),x86_64),true)
Configs += builtins-x86_64 profile-x86_64 san-x86_64 asan-x86_64 asan_cxx-x86_64 \
tsan-x86_64 msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64 dfsan-x86_64 \
- lsan-x86_64
+ lsan-x86_64 safestack-x86_64
Arch.builtins-x86_64 := x86_64
Arch.profile-x86_64 := x86_64
Arch.san-x86_64 := x86_64
@@ -76,6 +77,7 @@
Arch.ubsan_cxx-x86_64 := x86_64
Arch.dfsan-x86_64 := x86_64
Arch.lsan-x86_64 := x86_64
+Arch.safestack-x86_64 := x86_64
endif
endif
@@ -110,6 +112,10 @@
CFLAGS.ubsan_cxx-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS)
CFLAGS.dfsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
CFLAGS.lsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti
+CFLAGS.safestack-i386 := $(CFLAGS) -m32 -fPIE -fno-builtin -fno-exceptions \
+ -fno-rtti -fno-stack-protector -fno-safe-stack
+CFLAGS.safestack-x86_64 := $(CFLAGS) -m64 -fPIE -fno-builtin -fno-exceptions \
+ -fno-rtti -fno-stack-protector -fno-safe-stack
SHARED_LIBRARY.asan-arm-android := 1
ANDROID_COMMON_FLAGS := -target arm-linux-androideabi \
@@ -156,6 +162,8 @@
$(SanitizerCommonFunctions)
FUNCTIONS.lsan-x86_64 := $(LsanFunctions) $(InterceptionFunctions) \
$(SanitizerCommonFunctions)
+FUNCTIONS.safestack-i386 := $(SafeStackFunctions) $(InterceptionFunctions)
+FUNCTIONS.safestack-x86_64 := $(SafeStackFunctions) $(InterceptionFunctions)
# Always use optimized variants.
OPTIMIZED := 1
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -48,6 +48,9 @@
if(COMPILER_RT_HAS_UBSAN)
add_subdirectory(ubsan)
endif()
+ if(COMPILER_RT_HAS_SAFESTACK)
+ add_subdirectory(safestack)
+ endif()
endif()
if(COMPILER_RT_STANDALONE_BUILD)
Index: test/safestack/CMakeLists.txt
===================================================================
--- /dev/null
+++ test/safestack/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(SAFESTACK_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(SAFESTACK_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SAFESTACK_TEST_DEPS safetstack)
+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")
Index: test/safestack/check-buffer-copy.c
===================================================================
--- /dev/null
+++ test/safestack/check-buffer-copy.c
@@ -0,0 +1,19 @@
+// RUN: %clang_safestack %s -o %t
+// RUN: %run %t
+
+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';
+
+ // 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;
+}
Index: test/safestack/check-init.c
===================================================================
--- /dev/null
+++ test/safestack/check-init.c
@@ -0,0 +1,7 @@
+// RUN: %clang_safestack %s -o %t
+// RUN: %run %t
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
Index: test/safestack/check-overflow.c
===================================================================
--- /dev/null
+++ test/safestack/check-overflow.c
@@ -0,0 +1,20 @@
+// RUN: %clang_safestack %s -o %t
+// RUN: %run %t
+
+// RUN: %clang_nosafestack -fno-stack-protector %s -o %t
+// RUN: %run ! %t
+
+void fct(int *buffer)
+{
+ buffer[-1] = 36;
+ buffer[6] = 36;
+}
+
+int main(int argc, char **argv)
+{
+ int value1 = 42;
+ int buffer[5];
+ int value2 = 42;
+ fct(buffer);
+ return value1 != 42 || value2 != 42;
+}
Index: test/safestack/check-pthread-cleanup.c
===================================================================
--- /dev/null
+++ test/safestack/check-pthread-cleanup.c
@@ -0,0 +1,29 @@
+// RUN: %clang_safestack %s -pthread -o %t
+// RUN: %run ! %t
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#define BUFFER_SIZE (1 << 15)
+
+void *t1_start(void *ptr)
+{
+ char buffer[BUFFER_SIZE];
+ 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, BUFFER_SIZE);
+ return 0;
+}
Index: test/safestack/check-pthread.c
===================================================================
--- /dev/null
+++ test/safestack/check-pthread.c
@@ -0,0 +1,36 @@
+// RUN: %clang_safestack %s -pthread -o %t
+// RUN: %run %t
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.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));
+
+ 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;
+}
Index: test/safestack/lit.cfg
===================================================================
--- /dev/null
+++ test/safestack/lit.cfg
@@ -0,0 +1,20 @@
+# -*- 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-safe-stack ") )
+config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsafe-stack ") )
+
+# SafeStack tests are currently supported on Linux, FreeBSD and Darwin only.
+if config.host_os not in ['Linux', 'FreeBSD', 'Darwin']:
+ config.unsupported = True
Index: test/safestack/lit.site.cfg.in
===================================================================
--- /dev/null
+++ test/safestack/lit.site.cfg.in
@@ -0,0 +1,11 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Tool-specific config options.
+config.safestack_lit_binary_dir = "@SAFESTACK_LIT_BINARY_DIR@"
+
+# 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")
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits