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 has their own InitializeShadowMemory implementation.
17#if !SANITIZER_FUCHSIA
18
19#  include "asan_internal.h"
20#  include "asan_mapping.h"
21
22namespace __asan {
23
24static void ProtectGap(uptr addr, uptr size) {
25  if (!flags()->protect_shadow_gap) {
26    // The shadow gap is unprotected, so there is a chance that someone
27    // is actually using this memory. Which means it needs a shadow...
28    uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
29    uptr GapShadowEnd =
30        RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
31    if (Verbosity())
32      Printf(
33          "protect_shadow_gap=0:"
34          " not protecting shadow gap, allocating gap's shadow\n"
35          "|| `[%p, %p]` || ShadowGap's shadow ||\n",
36          (void*)GapShadowBeg, (void*)GapShadowEnd);
37    ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
38                             "unprotected gap shadow");
39    return;
40  }
41  __sanitizer::ProtectGap(addr, size, kZeroBaseShadowStart,
42                          kZeroBaseMaxShadowStart);
43}
44
45static void MaybeReportLinuxPIEBug() {
46#if SANITIZER_LINUX && \
47    (defined(__x86_64__) || defined(__aarch64__) || SANITIZER_RISCV64)
48  Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
49  Report(
50      "See https://github.com/google/sanitizers/issues/856 for possible "
51      "workarounds.\n");
52#endif
53}
54
55void InitializeShadowMemory() {
56  // Set the shadow memory address to uninitialized.
57  __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
58
59  uptr shadow_start = kLowShadowBeg;
60  // Detect if a dynamic shadow address must used and find a available location
61  // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
62  // expands to |__asan_shadow_memory_dynamic_address| which is
63  // |kDefaultShadowSentinel|.
64  bool full_shadow_is_available = false;
65  if (shadow_start == kDefaultShadowSentinel) {
66    shadow_start = FindDynamicShadowStart();
67    if (SANITIZER_LINUX) full_shadow_is_available = true;
68  }
69  // Update the shadow memory address (potentially) used by instrumentation.
70  __asan_shadow_memory_dynamic_address = shadow_start;
71
72  if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
73
74  if (!full_shadow_is_available)
75    full_shadow_is_available =
76        MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
77
78#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
79    !ASAN_FIXED_MAPPING
80  if (!full_shadow_is_available) {
81    kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
82    kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
83  }
84#endif
85
86  if (Verbosity()) PrintAddressSpaceLayout();
87
88  if (full_shadow_is_available) {
89    // mmap the low shadow plus at least one page at the left.
90    if (kLowShadowBeg)
91      ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
92    // mmap the high shadow.
93    ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
94    // protect the gap.
95    ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
96    CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
97  } else if (kMidMemBeg &&
98             MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
99             MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
100    CHECK(kLowShadowBeg != kLowShadowEnd);
101    // mmap the low shadow plus at least one page at the left.
102    ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
103    // mmap the mid shadow.
104    ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
105    // mmap the high shadow.
106    ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
107    // protect the gaps.
108    ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
109    ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
110    ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
111  } else {
112    Report(
113        "Shadow memory range interleaves with an existing memory mapping. "
114        "ASan cannot proceed correctly. ABORTING.\n");
115    Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
116           (void*)shadow_start, (void*)kHighShadowEnd);
117    MaybeReportLinuxPIEBug();
118    DumpProcessMap();
119    Die();
120  }
121}
122
123}  // namespace __asan
124
125#endif  // !SANITIZER_FUCHSIA
126