diff options
Diffstat (limited to 'libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc')
-rw-r--r-- | libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc | 155 |
1 files changed, 27 insertions, 128 deletions
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc index e754b26e693..36aaafdcc4b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc @@ -15,23 +15,25 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" +#include "sanitizer_freebsd.h" #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_atomic.h" +#include "sanitizer_symbolizer.h" + +#if SANITIZER_ANDROID || SANITIZER_FREEBSD +#include <dlfcn.h> // for dlsym() +#endif -#include <dlfcn.h> #include <pthread.h> #include <signal.h> #include <sys/resource.h> -#if SANITIZER_FREEBSD -#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h> -#endif -#include <unwind.h> #if SANITIZER_FREEBSD #include <pthread_np.h> +#include <osreldate.h> #define pthread_getattr_np pthread_attr_get_np #endif @@ -147,127 +149,6 @@ bool SanitizerGetThreadName(char *name, int max_len) { #endif } -//------------------------- SlowUnwindStack ----------------------------------- - -typedef struct { - uptr absolute_pc; - uptr stack_top; - uptr stack_size; -} backtrace_frame_t; - -extern "C" { -typedef void *(*acquire_my_map_info_list_func)(); -typedef void (*release_my_map_info_list_func)(void *map); -typedef sptr (*unwind_backtrace_signal_arch_func)( - void *siginfo, void *sigcontext, void *map_info_list, - backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth); -acquire_my_map_info_list_func acquire_my_map_info_list; -release_my_map_info_list_func release_my_map_info_list; -unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; -} // extern "C" - -#if SANITIZER_ANDROID -void SanitizerInitializeUnwinder() { - void *p = dlopen("libcorkscrew.so", RTLD_LAZY); - if (!p) { - VReport(1, - "Failed to open libcorkscrew.so. You may see broken stack traces " - "in SEGV reports."); - return; - } - acquire_my_map_info_list = - (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list"); - release_my_map_info_list = - (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list"); - unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym( - p, "unwind_backtrace_signal_arch"); - if (!acquire_my_map_info_list || !release_my_map_info_list || - !unwind_backtrace_signal_arch) { - VReport(1, - "Failed to find one of the required symbols in libcorkscrew.so. " - "You may see broken stack traces in SEGV reports."); - acquire_my_map_info_list = NULL; - unwind_backtrace_signal_arch = NULL; - release_my_map_info_list = NULL; - } -} -#endif - -#ifdef __arm__ -#define UNWIND_STOP _URC_END_OF_STACK -#define UNWIND_CONTINUE _URC_NO_REASON -#else -#define UNWIND_STOP _URC_NORMAL_STOP -#define UNWIND_CONTINUE _URC_NO_REASON -#endif - -uptr Unwind_GetIP(struct _Unwind_Context *ctx) { -#ifdef __arm__ - uptr val; - _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, - 15 /* r15 = PC */, _UVRSD_UINT32, &val); - CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); - // Clear the Thumb bit. - return val & ~(uptr)1; -#else - return _Unwind_GetIP(ctx); -#endif -} - -struct UnwindTraceArg { - StackTrace *stack; - uptr max_depth; -}; - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { - UnwindTraceArg *arg = (UnwindTraceArg*)param; - CHECK_LT(arg->stack->size, arg->max_depth); - uptr pc = Unwind_GetIP(ctx); - arg->stack->trace[arg->stack->size++] = pc; - if (arg->stack->size == arg->max_depth) return UNWIND_STOP; - return UNWIND_CONTINUE; -} - -void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { - CHECK_GE(max_depth, 2); - size = 0; - UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; - _Unwind_Backtrace(Unwind_Trace, &arg); - // We need to pop a few frames so that pc is on top. - uptr to_pop = LocatePcInTrace(pc); - // trace[0] belongs to the current function so we always pop it. - if (to_pop == 0) - to_pop = 1; - PopStackFrames(to_pop); - trace[0] = pc; -} - -void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, - uptr max_depth) { - CHECK_GE(max_depth, 2); - if (!unwind_backtrace_signal_arch) { - SlowUnwindStack(pc, max_depth); - return; - } - - void *map = acquire_my_map_info_list(); - CHECK(map); - InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax); - // siginfo argument appears to be unused. - sptr res = unwind_backtrace_signal_arch(/* siginfo */ NULL, context, map, - frames.data(), - /* ignore_depth */ 0, max_depth); - release_my_map_info_list(map); - if (res < 0) return; - CHECK_LE((uptr)res, kStackTraceMax); - - size = 0; - // +2 compensate for libcorkscrew unwinder returning addresses of call - // instructions instead of raw return addresses. - for (sptr i = 0; i < res; ++i) - trace[size++] = frames[i].absolute_pc + 2; -} - #if !SANITIZER_FREEBSD static uptr g_tls_size; #endif @@ -299,11 +180,11 @@ void InitTlsSize() { static atomic_uintptr_t kThreadDescriptorSize; uptr ThreadDescriptorSize() { - char buf[64]; uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); if (val) return val; #ifdef _CS_GNU_LIBC_VERSION + char buf[64]; uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { char *end; @@ -468,6 +349,10 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules, #else // SANITIZER_ANDROID # if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; +# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +# define Elf_Phdr XElf32_Phdr +# define dl_phdr_info xdl_phdr_info +# define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) # endif struct DlIteratePhdrData { @@ -504,7 +389,8 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { if (phdr->p_type == PT_LOAD) { uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; - cur_module->addAddressRange(cur_beg, cur_end); + bool executable = phdr->p_flags & PF_X; + cur_module->addAddressRange(cur_beg, cur_end, executable); } } return 0; @@ -527,6 +413,19 @@ void SetIndirectCallWrapper(uptr wrapper) { indirect_call_wrapper = wrapper; } +void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { + // Some kinds of sandboxes may forbid filesystem access, so we won't be able + // to read the file mappings from /proc/self/maps. Luckily, neither the + // process will be able to load additional libraries, so it's fine to use the + // cached mappings. + MemoryMappingLayout::CacheMemoryMappings(); + // Same for /proc/self/exe in the symbolizer. +#if !SANITIZER_GO + Symbolizer::GetOrInit()->PrepareForSandboxing(); + CovPrepareForSandboxing(args); +#endif +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX |