]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/asan/asan_shadow_setup.cc
Merge compiler-rt trunk r366426, resolve conflicts, and add
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / asan / asan_shadow_setup.cc
1 //===-- asan_shadow_setup.cc ----------------------------------------------===//
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.cc and asan_rtems.cc 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
25 // ---------------------- mmap -------------------- {{{1
26 // Reserve memory range [beg, end].
27 // We need to use inclusive range because end+1 may not be representable.
28 void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
29   CHECK_EQ((beg % GetMmapGranularity()), 0);
30   CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
31   uptr size = end - beg + 1;
32   DecreaseTotalMmap(size);  // Don't count the shadow against mmap_limit_mb.
33   if (!MmapFixedNoReserve(beg, size, name)) {
34     Report(
35         "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
36         "Perhaps you're using ulimit -v\n",
37         size);
38     Abort();
39   }
40   if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
41   if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
42 }
43
44 static void ProtectGap(uptr addr, uptr size) {
45   if (!flags()->protect_shadow_gap) {
46     // The shadow gap is unprotected, so there is a chance that someone
47     // is actually using this memory. Which means it needs a shadow...
48     uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
49     uptr GapShadowEnd =
50         RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
51     if (Verbosity())
52       Printf(
53           "protect_shadow_gap=0:"
54           " not protecting shadow gap, allocating gap's shadow\n"
55           "|| `[%p, %p]` || ShadowGap's shadow ||\n",
56           GapShadowBeg, GapShadowEnd);
57     ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
58                              "unprotected gap shadow");
59     return;
60   }
61   void *res = MmapFixedNoAccess(addr, size, "shadow gap");
62   if (addr == (uptr)res) return;
63   // A few pages at the start of the address space can not be protected.
64   // But we really want to protect as much as possible, to prevent this memory
65   // being returned as a result of a non-FIXED mmap().
66   if (addr == kZeroBaseShadowStart) {
67     uptr step = GetMmapGranularity();
68     while (size > step && addr < kZeroBaseMaxShadowStart) {
69       addr += step;
70       size -= step;
71       void *res = MmapFixedNoAccess(addr, size, "shadow gap");
72       if (addr == (uptr)res) return;
73     }
74   }
75
76   Report(
77       "ERROR: Failed to protect the shadow gap. "
78       "ASan cannot proceed correctly. ABORTING.\n");
79   DumpProcessMap();
80   Die();
81 }
82
83 static void MaybeReportLinuxPIEBug() {
84 #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
85   Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
86   Report(
87       "See https://github.com/google/sanitizers/issues/856 for possible "
88       "workarounds.\n");
89 #endif
90 }
91
92 void InitializeShadowMemory() {
93   // Set the shadow memory address to uninitialized.
94   __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
95
96   uptr shadow_start = kLowShadowBeg;
97   // Detect if a dynamic shadow address must used and find a available location
98   // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
99   // expands to |__asan_shadow_memory_dynamic_address| which is
100   // |kDefaultShadowSentinel|.
101   bool full_shadow_is_available = false;
102   if (shadow_start == kDefaultShadowSentinel) {
103     __asan_shadow_memory_dynamic_address = 0;
104     CHECK_EQ(0, kLowShadowBeg);
105     shadow_start = FindDynamicShadowStart();
106     if (SANITIZER_LINUX) full_shadow_is_available = true;
107   }
108   // Update the shadow memory address (potentially) used by instrumentation.
109   __asan_shadow_memory_dynamic_address = shadow_start;
110
111   if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
112
113   if (!full_shadow_is_available)
114     full_shadow_is_available =
115         MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
116
117 #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
118     !ASAN_FIXED_MAPPING
119   if (!full_shadow_is_available) {
120     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
121     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
122   }
123 #endif
124
125   if (Verbosity()) PrintAddressSpaceLayout();
126
127   if (full_shadow_is_available) {
128     // mmap the low shadow plus at least one page at the left.
129     if (kLowShadowBeg)
130       ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
131     // mmap the high shadow.
132     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
133     // protect the gap.
134     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
135     CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
136   } else if (kMidMemBeg &&
137              MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
138              MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
139     CHECK(kLowShadowBeg != kLowShadowEnd);
140     // mmap the low shadow plus at least one page at the left.
141     ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
142     // mmap the mid shadow.
143     ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
144     // mmap the high shadow.
145     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
146     // protect the gaps.
147     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
148     ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
149     ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
150   } else {
151     Report(
152         "Shadow memory range interleaves with an existing memory mapping. "
153         "ASan cannot proceed correctly. ABORTING.\n");
154     Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
155            shadow_start, kHighShadowEnd);
156     MaybeReportLinuxPIEBug();
157     DumpProcessMap();
158     Die();
159   }
160 }
161
162 }  // namespace __asan
163
164 #endif  // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS