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