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 | |
22 | namespace __asan { |
23 | |
24 | static 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), boundary: GetPageSizeCached()); |
29 | uptr GapShadowEnd = |
30 | RoundUpTo(MEM_TO_SHADOW(addr + size), boundary: GetPageSizeCached()) - 1; |
31 | if (Verbosity()) |
32 | Printf( |
33 | format: "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(beg: GapShadowBeg, end: GapShadowEnd, |
38 | name: "unprotected gap shadow" ); |
39 | return; |
40 | } |
41 | __sanitizer::ProtectGap(addr, size, kZeroBaseShadowStart, |
42 | kZeroBaseMaxShadowStart); |
43 | } |
44 | |
45 | static void MaybeReportLinuxPIEBug() { |
46 | #if SANITIZER_LINUX && \ |
47 | (defined(__x86_64__) || defined(__aarch64__) || SANITIZER_RISCV64) |
48 | Report(format: "This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n" ); |
49 | Report( |
50 | format: "See https://github.com/google/sanitizers/issues/856 for possible " |
51 | "workarounds.\n" ); |
52 | #endif |
53 | } |
54 | |
55 | void 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(range_start: 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(beg: shadow_start, kLowShadowEnd, name: "low shadow" ); |
92 | // mmap the high shadow. |
93 | ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, name: "high shadow" ); |
94 | // protect the gap. |
95 | ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); |
96 | CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); |
97 | } else if (kMidMemBeg && |
98 | MemoryRangeIsAvailable(range_start: shadow_start, range_end: kMidMemBeg - 1) && |
99 | MemoryRangeIsAvailable(range_start: kMidMemEnd + 1, kHighShadowEnd)) { |
100 | CHECK(kLowShadowBeg != kLowShadowEnd); |
101 | // mmap the low shadow plus at least one page at the left. |
102 | ReserveShadowMemoryRange(beg: shadow_start, kLowShadowEnd, name: "low shadow" ); |
103 | // mmap the mid shadow. |
104 | ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, name: "mid shadow" ); |
105 | // mmap the high shadow. |
106 | ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, name: "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 | format: "Shadow memory range interleaves with an existing memory mapping. " |
114 | "ASan cannot proceed correctly. ABORTING.\n" ); |
115 | Report(format: "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 | |