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