1353944Sdim//===-- asan_shadow_setup.cpp ---------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker.
10353944Sdim//
11353944Sdim// Set up the shadow memory.
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim
14353944Sdim#include "sanitizer_common/sanitizer_platform.h"
15353944Sdim
16353944Sdim// asan_fuchsia.cpp and asan_rtems.cpp have their own
17353944Sdim// InitializeShadowMemory implementation.
18353944Sdim#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
19353944Sdim
20353944Sdim#include "asan_internal.h"
21353944Sdim#include "asan_mapping.h"
22353944Sdim
23353944Sdimnamespace __asan {
24353944Sdim
25353944Sdim// ---------------------- mmap -------------------- {{{1
26353944Sdim// Reserve memory range [beg, end].
27353944Sdim// We need to use inclusive range because end+1 may not be representable.
28353944Sdimvoid ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
29353944Sdim  CHECK_EQ((beg % GetMmapGranularity()), 0);
30353944Sdim  CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
31353944Sdim  uptr size = end - beg + 1;
32353944Sdim  DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb.
33353944Sdim  if (!MmapFixedSuperNoReserve(beg, size, name)) {
34353944Sdim    Report(
35353944Sdim        "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
36353944Sdim        "Perhaps you're using ulimit -v\n",
37353944Sdim        size);
38353944Sdim    Abort();
39353944Sdim  }
40353944Sdim  if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
41353944Sdim}
42353944Sdim
43353944Sdimstatic void ProtectGap(uptr addr, uptr size) {
44353944Sdim  if (!flags()->protect_shadow_gap) {
45353944Sdim    // The shadow gap is unprotected, so there is a chance that someone
46353944Sdim    // is actually using this memory. Which means it needs a shadow...
47353944Sdim    uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
48353944Sdim    uptr GapShadowEnd =
49353944Sdim        RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
50353944Sdim    if (Verbosity())
51353944Sdim      Printf(
52353944Sdim          "protect_shadow_gap=0:"
53353944Sdim          " not protecting shadow gap, allocating gap's shadow\n"
54353944Sdim          "|| `[%p, %p]` || ShadowGap's shadow ||\n",
55353944Sdim          GapShadowBeg, GapShadowEnd);
56353944Sdim    ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
57353944Sdim                             "unprotected gap shadow");
58353944Sdim    return;
59353944Sdim  }
60353944Sdim  void *res = MmapFixedNoAccess(addr, size, "shadow gap");
61353944Sdim  if (addr == (uptr)res) return;
62353944Sdim  // A few pages at the start of the address space can not be protected.
63353944Sdim  // But we really want to protect as much as possible, to prevent this memory
64353944Sdim  // being returned as a result of a non-FIXED mmap().
65353944Sdim  if (addr == kZeroBaseShadowStart) {
66353944Sdim    uptr step = GetMmapGranularity();
67353944Sdim    while (size > step && addr < kZeroBaseMaxShadowStart) {
68353944Sdim      addr += step;
69353944Sdim      size -= step;
70353944Sdim      void *res = MmapFixedNoAccess(addr, size, "shadow gap");
71353944Sdim      if (addr == (uptr)res) return;
72353944Sdim    }
73353944Sdim  }
74353944Sdim
75353944Sdim  Report(
76353944Sdim      "ERROR: Failed to protect the shadow gap. "
77353944Sdim      "ASan cannot proceed correctly. ABORTING.\n");
78353944Sdim  DumpProcessMap();
79353944Sdim  Die();
80353944Sdim}
81353944Sdim
82353944Sdimstatic void MaybeReportLinuxPIEBug() {
83353944Sdim#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
84353944Sdim  Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
85353944Sdim  Report(
86353944Sdim      "See https://github.com/google/sanitizers/issues/856 for possible "
87353944Sdim      "workarounds.\n");
88353944Sdim#endif
89353944Sdim}
90353944Sdim
91353944Sdimvoid InitializeShadowMemory() {
92353944Sdim  // Set the shadow memory address to uninitialized.
93353944Sdim  __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
94353944Sdim
95353944Sdim  uptr shadow_start = kLowShadowBeg;
96353944Sdim  // Detect if a dynamic shadow address must used and find a available location
97353944Sdim  // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
98353944Sdim  // expands to |__asan_shadow_memory_dynamic_address| which is
99353944Sdim  // |kDefaultShadowSentinel|.
100353944Sdim  bool full_shadow_is_available = false;
101353944Sdim  if (shadow_start == kDefaultShadowSentinel) {
102353944Sdim    __asan_shadow_memory_dynamic_address = 0;
103353944Sdim    CHECK_EQ(0, kLowShadowBeg);
104353944Sdim    shadow_start = FindDynamicShadowStart();
105353944Sdim    if (SANITIZER_LINUX) full_shadow_is_available = true;
106353944Sdim  }
107353944Sdim  // Update the shadow memory address (potentially) used by instrumentation.
108353944Sdim  __asan_shadow_memory_dynamic_address = shadow_start;
109353944Sdim
110353944Sdim  if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
111353944Sdim
112353944Sdim  if (!full_shadow_is_available)
113353944Sdim    full_shadow_is_available =
114353944Sdim        MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
115353944Sdim
116353944Sdim#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
117353944Sdim    !ASAN_FIXED_MAPPING
118353944Sdim  if (!full_shadow_is_available) {
119353944Sdim    kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
120353944Sdim    kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
121353944Sdim  }
122353944Sdim#endif
123353944Sdim
124353944Sdim  if (Verbosity()) PrintAddressSpaceLayout();
125353944Sdim
126353944Sdim  if (full_shadow_is_available) {
127353944Sdim    // mmap the low shadow plus at least one page at the left.
128353944Sdim    if (kLowShadowBeg)
129353944Sdim      ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
130353944Sdim    // mmap the high shadow.
131353944Sdim    ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
132353944Sdim    // protect the gap.
133353944Sdim    ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
134353944Sdim    CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
135353944Sdim  } else if (kMidMemBeg &&
136353944Sdim             MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
137353944Sdim             MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
138353944Sdim    CHECK(kLowShadowBeg != kLowShadowEnd);
139353944Sdim    // mmap the low shadow plus at least one page at the left.
140353944Sdim    ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
141353944Sdim    // mmap the mid shadow.
142353944Sdim    ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
143353944Sdim    // mmap the high shadow.
144353944Sdim    ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
145353944Sdim    // protect the gaps.
146353944Sdim    ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
147353944Sdim    ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
148353944Sdim    ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
149353944Sdim  } else {
150353944Sdim    Report(
151353944Sdim        "Shadow memory range interleaves with an existing memory mapping. "
152353944Sdim        "ASan cannot proceed correctly. ABORTING.\n");
153353944Sdim    Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
154353944Sdim           shadow_start, kHighShadowEnd);
155353944Sdim    MaybeReportLinuxPIEBug();
156353944Sdim    DumpProcessMap();
157353944Sdim    Die();
158353944Sdim  }
159353944Sdim}
160353944Sdim
161353944Sdim}  // namespace __asan
162353944Sdim
163353944Sdim#endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
164