xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_shadow_setup.cpp (revision f81cdf24ba5436367377f7c8e8f51f6df2a75ca7)
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), 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 
45 static 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 
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(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