brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.0 KiB · d2c2a39 Raw
292 lines · cpp
1//===-- asan_linux.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of AddressSanitizer, an address sanity checker.10//11// Linux-specific details.12//===----------------------------------------------------------------------===//13 14#include "sanitizer_common/sanitizer_platform.h"15#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \16    SANITIZER_SOLARIS || SANITIZER_HAIKU17 18#  if SANITIZER_HAIKU19#    define _DEFAULT_SOURCE20#  endif21 22#  include <dlfcn.h>23#  include <fcntl.h>24#  include <limits.h>25#  include <pthread.h>26#  include <stdio.h>27#  include <sys/mman.h>28#  include <sys/resource.h>29#  if !SANITIZER_HAIKU30#    include <sys/syscall.h>31#  endif32#  include <sys/time.h>33#  include <sys/types.h>34#  include <unistd.h>35#  include <unwind.h>36 37#  include "asan_interceptors.h"38#  include "asan_internal.h"39#  include "asan_premap_shadow.h"40#  include "asan_thread.h"41#  include "sanitizer_common/sanitizer_flags.h"42#  include "sanitizer_common/sanitizer_hash.h"43#  include "sanitizer_common/sanitizer_libc.h"44#  include "sanitizer_common/sanitizer_procmaps.h"45 46#  if SANITIZER_FREEBSD || SANITIZER_HAIKU47#    include <sys/link_elf.h>48#  endif49 50#  if SANITIZER_LINUX51#    include <sys/personality.h>52#  endif53 54#  if SANITIZER_SOLARIS55#    include <link.h>56#  endif57 58#  if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS59#    include <ucontext.h>60#  elif SANITIZER_NETBSD61#    include <link_elf.h>62#    include <ucontext.h>63#  elif SANITIZER_HAIKU64extern "C" void *_DYNAMIC;65#  else66#    include <link.h>67#    include <sys/ucontext.h>68#  endif69 70typedef enum {71  ASAN_RT_VERSION_UNDEFINED = 0,72  ASAN_RT_VERSION_DYNAMIC,73  ASAN_RT_VERSION_STATIC,74} asan_rt_version_t;75 76// FIXME: perhaps also store abi version here?77extern "C" {78SANITIZER_INTERFACE_ATTRIBUTE79asan_rt_version_t __asan_rt_version;80}81 82namespace __asan {83 84void InitializePlatformInterceptors() {}85void InitializePlatformExceptionHandlers() {}86bool IsSystemHeapAddress(uptr addr) { return false; }87 88#  if ASAN_PREMAP_SHADOW89uptr FindPremappedShadowStart(uptr shadow_size_bytes) {90  uptr granularity = GetMmapGranularity();91  uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);92  uptr premap_shadow_size = PremapShadowSize();93  uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);94  // We may have mapped too much. Release extra memory.95  UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);96  return shadow_start;97}98#  endif99 100uptr FindDynamicShadowStart() {101  uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);102#  if ASAN_PREMAP_SHADOW103  if (!PremapShadowFailed())104    return FindPremappedShadowStart(shadow_size_bytes);105#  endif106 107  return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE,108                          /*min_shadow_base_alignment*/ 0, kHighMemEnd,109                          GetMmapGranularity());110}111 112void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {113  UNIMPLEMENTED();114}115 116void FlushUnneededASanShadowMemory(uptr p, uptr size) {117  // Since asan's mapping is compacting, the shadow chunk may be118  // not page-aligned, so we only flush the page-aligned portion.119  ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));120}121 122void TryReExecWithoutASLR() {123#    if SANITIZER_LINUX124  // ASLR personality check.125  // Caution: 'personality' is sometimes forbidden by sandboxes, so only call126  // this function as a last resort (when the memory mapping is incompatible127  // and ASan would fail anyway).128  int old_personality = personality(0xffffffff);129  if (old_personality == -1) {130    VReport(1, "WARNING: unable to run personality check.\n");131    return;132  }133 134  bool aslr_on = (old_personality & ADDR_NO_RANDOMIZE) == 0;135 136  if (aslr_on) {137    // Disable ASLR if the memory layout was incompatible.138    // Alternatively, we could just keep re-execing until we get lucky139    // with a compatible randomized layout, but the risk is that if it's140    // not an ASLR-related issue, we will be stuck in an infinite loop of141    // re-execing (unless we change ReExec to pass a parameter of the142    // number of retries allowed.)143    VReport(1,144            "WARNING: AddressSanitizer: memory layout is incompatible, "145            "possibly due to high-entropy ASLR.\n"146            "Re-execing with fixed virtual address space.\n"147            "N.B. reducing ASLR entropy is preferable.\n");148    CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);149 150    ReExec();151  }152#    endif153}154 155#  if SANITIZER_ANDROID156// FIXME: should we do anything for Android?157void AsanCheckDynamicRTPrereqs() {}158void AsanCheckIncompatibleRT() {}159#  else160static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,161                                void *data) {162  VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name,163          (void *)info->dlpi_addr);164 165  const char **name = (const char **)data;166 167  // Ignore first entry (the main program)168  if (!*name) {169    *name = "";170    return 0;171  }172 173#    if SANITIZER_HAIKU174  if (!info->dlpi_name[0] ||175      internal_strncmp(info->dlpi_name, "/boot/system/runtime_loader",176                       sizeof("/boot/system/runtime_loader") - 1) == 0)177    return 0;178#    endif179#    if SANITIZER_LINUX180  // Ignore vDSO. glibc versions earlier than 2.15 (and some patched181  // by distributors) return an empty name for the vDSO entry, so182  // detect this as well.183  if (!info->dlpi_name[0] ||184      internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)185    return 0;186#    endif187#    if SANITIZER_FREEBSD188  // Ignore vDSO.189  if (internal_strcmp(info->dlpi_name, "[vdso]") == 0)190    return 0;191#    endif192 193  *name = info->dlpi_name;194  return 1;195}196 197static bool IsDynamicRTName(const char *libname) {198  return internal_strstr(libname, "libclang_rt.asan") ||199         internal_strstr(libname, "libasan.so");200}201 202static void ReportIncompatibleRT() {203  Report("Your application is linked against incompatible ASan runtimes.\n");204  Die();205}206 207void AsanCheckDynamicRTPrereqs() {208  if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)209    return;210 211  // Ensure that dynamic RT is the first DSO in the list212  const char *first_dso_name = nullptr;213  dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);214  if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) {215    Report(216        "ASan runtime does not come first in initial library list; "217        "you should either link runtime to your application or "218        "manually preload it with LD_PRELOAD.\n");219    Die();220  }221}222 223void AsanCheckIncompatibleRT() {224  if (ASAN_DYNAMIC) {225    if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {226      __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;227    } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {228      ReportIncompatibleRT();229    }230  } else {231    if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {232      // Ensure that dynamic runtime is not present. We should detect it233      // as early as possible, otherwise ASan interceptors could bind to234      // the functions in dynamic ASan runtime instead of the functions in235      // system libraries, causing crashes later in ASan initialization.236      MemoryMappingLayout proc_maps(/*cache_enabled*/ true);237      char filename[PATH_MAX];238      MemoryMappedSegment segment(filename, sizeof(filename));239      while (proc_maps.Next(&segment)) {240        if (IsDynamicRTName(segment.filename)) {241          ReportIncompatibleRT();242        }243      }244      __asan_rt_version = ASAN_RT_VERSION_STATIC;245    } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {246      ReportIncompatibleRT();247    }248  }249}250#  endif  // SANITIZER_ANDROID251 252#  if ASAN_INTERCEPT_SWAPCONTEXT253constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;254 255static int HashContextStack(const ucontext_t &ucp) {256  MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);257  hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));258  hash.add(ucp.uc_stack.ss_size);259  return static_cast<int>(hash.get());260}261 262void SignContextStack(void *context) {263  ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);264  ucp->uc_stack.ss_flags = HashContextStack(*ucp);265}266 267void ReadContextStack(void *context, uptr *stack, uptr *ssize) {268  const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);269  if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) {270    *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);271    *ssize = ucp->uc_stack.ss_size;272    return;273  }274  *stack = 0;275  *ssize = 0;276}277#  endif  // ASAN_INTERCEPT_SWAPCONTEXT278 279void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }280 281bool HandleDlopenInit() {282  // Not supported on this platform.283  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,284                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");285  return false;286}287 288}  // namespace __asan289 290#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||291        // SANITIZER_SOLARIS || SANITIZER_HAIKU292