Home | History | Annotate | Line # | Download | only in asan
      1 //===-- asan_linux.cc -----------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is a part of AddressSanitizer, an address sanity checker.
     11 //
     12 // Linux-specific details.
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_platform.h"
     16 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
     17     SANITIZER_SOLARIS
     18 
     19 #include "asan_interceptors.h"
     20 #include "asan_internal.h"
     21 #include "asan_premap_shadow.h"
     22 #include "asan_thread.h"
     23 #include "sanitizer_common/sanitizer_flags.h"
     24 #include "sanitizer_common/sanitizer_freebsd.h"
     25 #include "sanitizer_common/sanitizer_libc.h"
     26 #include "sanitizer_common/sanitizer_procmaps.h"
     27 
     28 #include <sys/time.h>
     29 #include <sys/resource.h>
     30 #include <sys/mman.h>
     31 #include <sys/syscall.h>
     32 #include <sys/types.h>
     33 #include <dlfcn.h>
     34 #include <fcntl.h>
     35 #include <limits.h>
     36 #include <pthread.h>
     37 #include <stdio.h>
     38 #include <unistd.h>
     39 #include <unwind.h>
     40 
     41 #if SANITIZER_FREEBSD
     42 #include <sys/link_elf.h>
     43 #endif
     44 
     45 #if SANITIZER_SOLARIS
     46 #include <link.h>
     47 #endif
     48 
     49 #if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
     50 #include <ucontext.h>
     51 extern "C" void* _DYNAMIC;
     52 #elif SANITIZER_NETBSD
     53 #include <link_elf.h>
     54 #include <ucontext.h>
     55 extern Elf_Dyn _DYNAMIC;
     56 #else
     57 #include <sys/ucontext.h>
     58 #include <link.h>
     59 #endif
     60 
     61 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
     62 // 32-bit mode.
     63 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
     64   __FreeBSD_version <= 902001  // v9.2
     65 #define ucontext_t xucontext_t
     66 #endif
     67 
     68 typedef enum {
     69   ASAN_RT_VERSION_UNDEFINED = 0,
     70   ASAN_RT_VERSION_DYNAMIC,
     71   ASAN_RT_VERSION_STATIC,
     72 } asan_rt_version_t;
     73 
     74 // FIXME: perhaps also store abi version here?
     75 extern "C" {
     76 SANITIZER_INTERFACE_ATTRIBUTE
     77 asan_rt_version_t  __asan_rt_version;
     78 }
     79 
     80 namespace __asan {
     81 
     82 void InitializePlatformInterceptors() {}
     83 void InitializePlatformExceptionHandlers() {}
     84 bool IsSystemHeapAddress (uptr addr) { return false; }
     85 
     86 void *AsanDoesNotSupportStaticLinkage() {
     87   // This will fail to link with -static.
     88   return &_DYNAMIC;  // defined in link.h
     89 }
     90 
     91 static void UnmapFromTo(uptr from, uptr to) {
     92   CHECK(to >= from);
     93   if (to == from) return;
     94   uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
     95   if (UNLIKELY(internal_iserror(res))) {
     96     Report(
     97         "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
     98         "%p\n",
     99         to - from, to - from, from);
    100     CHECK("unable to unmap" && 0);
    101   }
    102 }
    103 
    104 #if ASAN_PREMAP_SHADOW
    105 uptr FindPremappedShadowStart() {
    106   uptr granularity = GetMmapGranularity();
    107   uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
    108   uptr premap_shadow_size = PremapShadowSize();
    109   uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
    110   // We may have mapped too much. Release extra memory.
    111   UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
    112   return shadow_start;
    113 }
    114 #endif
    115 
    116 uptr FindDynamicShadowStart() {
    117 #if ASAN_PREMAP_SHADOW
    118   if (!PremapShadowFailed())
    119     return FindPremappedShadowStart();
    120 #endif
    121 
    122   uptr granularity = GetMmapGranularity();
    123   uptr alignment = granularity * 8;
    124   uptr left_padding = granularity;
    125   uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
    126   uptr map_size = shadow_size + left_padding + alignment;
    127 
    128   uptr map_start = (uptr)MmapNoAccess(map_size);
    129   CHECK_NE(map_start, ~(uptr)0);
    130 
    131   uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
    132   UnmapFromTo(map_start, shadow_start - left_padding);
    133   UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
    134 
    135   return shadow_start;
    136 }
    137 
    138 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
    139   UNIMPLEMENTED();
    140 }
    141 
    142 #if SANITIZER_ANDROID
    143 // FIXME: should we do anything for Android?
    144 void AsanCheckDynamicRTPrereqs() {}
    145 void AsanCheckIncompatibleRT() {}
    146 #else
    147 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
    148                                 void *data) {
    149   VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
    150           info->dlpi_name, info->dlpi_addr);
    151 
    152   // Continue until the first dynamic library is found
    153   if (!info->dlpi_name || info->dlpi_name[0] == 0)
    154     return 0;
    155 
    156   // Ignore vDSO
    157   if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
    158     return 0;
    159 
    160 #if SANITIZER_FREEBSD || SANITIZER_NETBSD
    161   // Ignore first entry (the main program)
    162   char **p = (char **)data;
    163   if (!(*p)) {
    164     *p = (char *)-1;
    165     return 0;
    166   }
    167 #endif
    168 
    169 #if SANITIZER_SOLARIS
    170   // Ignore executable on Solaris
    171   if (info->dlpi_addr == 0)
    172     return 0;
    173 #endif
    174 
    175   *(const char **)data = info->dlpi_name;
    176   return 1;
    177 }
    178 
    179 static bool IsDynamicRTName(const char *libname) {
    180   return internal_strstr(libname, "libclang_rt.asan") ||
    181     internal_strstr(libname, "libasan.so");
    182 }
    183 
    184 static void ReportIncompatibleRT() {
    185   Report("Your application is linked against incompatible ASan runtimes.\n");
    186   Die();
    187 }
    188 
    189 void AsanCheckDynamicRTPrereqs() {
    190   if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
    191     return;
    192 
    193   // Ensure that dynamic RT is the first DSO in the list
    194   const char *first_dso_name = nullptr;
    195   dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
    196   if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
    197     Report("ASan runtime does not come first in initial library list; "
    198            "you should either link runtime to your application or "
    199            "manually preload it with LD_PRELOAD.\n");
    200     Die();
    201   }
    202 }
    203 
    204 void AsanCheckIncompatibleRT() {
    205   if (ASAN_DYNAMIC) {
    206     if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
    207       __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
    208     } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
    209       ReportIncompatibleRT();
    210     }
    211   } else {
    212     if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
    213       // Ensure that dynamic runtime is not present. We should detect it
    214       // as early as possible, otherwise ASan interceptors could bind to
    215       // the functions in dynamic ASan runtime instead of the functions in
    216       // system libraries, causing crashes later in ASan initialization.
    217       MemoryMappingLayout proc_maps(/*cache_enabled*/true);
    218       char filename[PATH_MAX];
    219       MemoryMappedSegment segment(filename, sizeof(filename));
    220       while (proc_maps.Next(&segment)) {
    221         if (IsDynamicRTName(segment.filename)) {
    222           Report("Your application is linked against "
    223                  "incompatible ASan runtimes.\n");
    224           Die();
    225         }
    226       }
    227       __asan_rt_version = ASAN_RT_VERSION_STATIC;
    228     } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
    229       ReportIncompatibleRT();
    230     }
    231   }
    232 }
    233 #endif // SANITIZER_ANDROID
    234 
    235 #if !SANITIZER_ANDROID
    236 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
    237   ucontext_t *ucp = (ucontext_t*)context;
    238   *stack = (uptr)ucp->uc_stack.ss_sp;
    239   *ssize = ucp->uc_stack.ss_size;
    240 }
    241 #else
    242 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
    243   UNIMPLEMENTED();
    244 }
    245 #endif
    246 
    247 void *AsanDlSymNext(const char *sym) {
    248   return dlsym(RTLD_NEXT, sym);
    249 }
    250 
    251 bool HandleDlopenInit() {
    252   // Not supported on this platform.
    253   static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
    254                 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
    255   return false;
    256 }
    257 
    258 } // namespace __asan
    259 
    260 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
    261         // SANITIZER_SOLARIS
    262