Home | History | Annotate | Line # | Download | only in asan
      1 //===-- asan_shadow_setup.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 // Set up the shadow memory.
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_platform.h"
     16 
     17 // asan_fuchsia.cc and asan_rtems.cc have their own
     18 // InitializeShadowMemory implementation.
     19 #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
     20 
     21 #include "asan_internal.h"
     22 #include "asan_mapping.h"
     23 
     24 namespace __asan {
     25 
     26 // ---------------------- mmap -------------------- {{{1
     27 // Reserve memory range [beg, end].
     28 // We need to use inclusive range because end+1 may not be representable.
     29 void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
     30   CHECK_EQ((beg % GetMmapGranularity()), 0);
     31   CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
     32   uptr size = end - beg + 1;
     33   DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb.
     34   if (!MmapFixedNoReserve(beg, size, name)) {
     35     Report(
     36         "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
     37         "Perhaps you're using ulimit -v\n",
     38         size);
     39     Abort();
     40   }
     41   if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
     42   if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
     43 }
     44 
     45 static void ProtectGap(uptr addr, uptr size) {
     46   if (!flags()->protect_shadow_gap) {
     47     // The shadow gap is unprotected, so there is a chance that someone
     48     // is actually using this memory. Which means it needs a shadow...
     49     uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
     50     uptr GapShadowEnd =
     51         RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
     52     if (Verbosity())
     53       Printf(
     54           "protect_shadow_gap=0:"
     55           " not protecting shadow gap, allocating gap's shadow\n"
     56           "|| `[%p, %p]` || ShadowGap's shadow ||\n",
     57           GapShadowBeg, GapShadowEnd);
     58     ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
     59                              "unprotected gap shadow");
     60     return;
     61   }
     62   void *res = MmapFixedNoAccess(addr, size, "shadow gap");
     63   if (addr == (uptr)res) return;
     64   // A few pages at the start of the address space can not be protected.
     65   // But we really want to protect as much as possible, to prevent this memory
     66   // being returned as a result of a non-FIXED mmap().
     67   if (addr == kZeroBaseShadowStart) {
     68     uptr step = GetMmapGranularity();
     69     while (size > step && addr < kZeroBaseMaxShadowStart) {
     70       addr += step;
     71       size -= step;
     72       void *res = MmapFixedNoAccess(addr, size, "shadow gap");
     73       if (addr == (uptr)res) return;
     74     }
     75   }
     76 
     77   Report(
     78       "ERROR: Failed to protect the shadow gap. "
     79       "ASan cannot proceed correctly. ABORTING.\n");
     80   DumpProcessMap();
     81   Die();
     82 }
     83 
     84 static void MaybeReportLinuxPIEBug() {
     85 #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
     86   Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
     87   Report(
     88       "See https://github.com/google/sanitizers/issues/856 for possible "
     89       "workarounds.\n");
     90 #endif
     91 }
     92 
     93 void InitializeShadowMemory() {
     94   // Set the shadow memory address to uninitialized.
     95   __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
     96 
     97   uptr shadow_start = kLowShadowBeg;
     98   // Detect if a dynamic shadow address must used and find a available location
     99   // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
    100   // expands to |__asan_shadow_memory_dynamic_address| which is
    101   // |kDefaultShadowSentinel|.
    102   bool full_shadow_is_available = false;
    103   if (shadow_start == kDefaultShadowSentinel) {
    104     __asan_shadow_memory_dynamic_address = 0;
    105     CHECK_EQ(0, kLowShadowBeg);
    106     shadow_start = FindDynamicShadowStart();
    107     if (SANITIZER_LINUX) full_shadow_is_available = true;
    108   }
    109   // Update the shadow memory address (potentially) used by instrumentation.
    110   __asan_shadow_memory_dynamic_address = shadow_start;
    111 
    112   if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
    113 
    114   if (!full_shadow_is_available)
    115     full_shadow_is_available =
    116         MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
    117 
    118 #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
    119     !ASAN_FIXED_MAPPING
    120   if (!full_shadow_is_available) {
    121     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
    122     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
    123   }
    124 #endif
    125 
    126   if (Verbosity()) PrintAddressSpaceLayout();
    127 
    128   if (full_shadow_is_available) {
    129     // mmap the low shadow plus at least one page at the left.
    130     if (kLowShadowBeg)
    131       ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
    132     // mmap the high shadow.
    133     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
    134     // protect the gap.
    135     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
    136     CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
    137   } else if (kMidMemBeg &&
    138              MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
    139              MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
    140     CHECK(kLowShadowBeg != kLowShadowEnd);
    141     // mmap the low shadow plus at least one page at the left.
    142     ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
    143     // mmap the mid shadow.
    144     ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
    145     // mmap the high shadow.
    146     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
    147     // protect the gaps.
    148     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
    149     ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
    150     ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
    151   } else {
    152     Report(
    153         "Shadow memory range interleaves with an existing memory mapping. "
    154         "ASan cannot proceed correctly. ABORTING.\n");
    155     Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
    156            shadow_start, kHighShadowEnd);
    157     MaybeReportLinuxPIEBug();
    158     DumpProcessMap();
    159     Die();
    160   }
    161 }
    162 
    163 }  // namespace __asan
    164 
    165 #endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
    166