xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_shadow_setup.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
168d75effSDimitry Andric //===-- asan_shadow_setup.cpp ---------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Set up the shadow memory.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
1568d75effSDimitry Andric 
16fe6060f1SDimitry Andric // asan_fuchsia.cpp has their own InitializeShadowMemory implementation.
17fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA
1868d75effSDimitry Andric 
1968d75effSDimitry Andric #  include "asan_internal.h"
2068d75effSDimitry Andric #  include "asan_mapping.h"
2168d75effSDimitry Andric 
2268d75effSDimitry Andric namespace __asan {
2368d75effSDimitry Andric 
ProtectGap(uptr addr,uptr size)2468d75effSDimitry Andric static void ProtectGap(uptr addr, uptr size) {
2568d75effSDimitry Andric   if (!flags()->protect_shadow_gap) {
2668d75effSDimitry Andric     // The shadow gap is unprotected, so there is a chance that someone
2768d75effSDimitry Andric     // is actually using this memory. Which means it needs a shadow...
2868d75effSDimitry Andric     uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
2968d75effSDimitry Andric     uptr GapShadowEnd =
3068d75effSDimitry Andric         RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
3168d75effSDimitry Andric     if (Verbosity())
3268d75effSDimitry Andric       Printf(
3368d75effSDimitry Andric           "protect_shadow_gap=0:"
3468d75effSDimitry Andric           " not protecting shadow gap, allocating gap's shadow\n"
3568d75effSDimitry Andric           "|| `[%p, %p]` || ShadowGap's shadow ||\n",
36*349cc55cSDimitry Andric           (void*)GapShadowBeg, (void*)GapShadowEnd);
3768d75effSDimitry Andric     ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
3868d75effSDimitry Andric                              "unprotected gap shadow");
3968d75effSDimitry Andric     return;
4068d75effSDimitry Andric   }
41e8d8bef9SDimitry Andric   __sanitizer::ProtectGap(addr, size, kZeroBaseShadowStart,
42e8d8bef9SDimitry Andric                           kZeroBaseMaxShadowStart);
4368d75effSDimitry Andric }
4468d75effSDimitry Andric 
MaybeReportLinuxPIEBug()4568d75effSDimitry Andric static void MaybeReportLinuxPIEBug() {
46e8d8bef9SDimitry Andric #if SANITIZER_LINUX && \
47e8d8bef9SDimitry Andric     (defined(__x86_64__) || defined(__aarch64__) || SANITIZER_RISCV64)
4868d75effSDimitry Andric   Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
4968d75effSDimitry Andric   Report(
5068d75effSDimitry Andric       "See https://github.com/google/sanitizers/issues/856 for possible "
5168d75effSDimitry Andric       "workarounds.\n");
5268d75effSDimitry Andric #endif
5368d75effSDimitry Andric }
5468d75effSDimitry Andric 
InitializeShadowMemory()5568d75effSDimitry Andric void InitializeShadowMemory() {
5668d75effSDimitry Andric   // Set the shadow memory address to uninitialized.
5768d75effSDimitry Andric   __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
5868d75effSDimitry Andric 
5968d75effSDimitry Andric   uptr shadow_start = kLowShadowBeg;
6068d75effSDimitry Andric   // Detect if a dynamic shadow address must used and find a available location
6168d75effSDimitry Andric   // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
6268d75effSDimitry Andric   // expands to |__asan_shadow_memory_dynamic_address| which is
6368d75effSDimitry Andric   // |kDefaultShadowSentinel|.
6468d75effSDimitry Andric   bool full_shadow_is_available = false;
6568d75effSDimitry Andric   if (shadow_start == kDefaultShadowSentinel) {
6668d75effSDimitry Andric     shadow_start = FindDynamicShadowStart();
6768d75effSDimitry Andric     if (SANITIZER_LINUX) full_shadow_is_available = true;
6868d75effSDimitry Andric   }
6968d75effSDimitry Andric   // Update the shadow memory address (potentially) used by instrumentation.
7068d75effSDimitry Andric   __asan_shadow_memory_dynamic_address = shadow_start;
7168d75effSDimitry Andric 
7268d75effSDimitry Andric   if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
7368d75effSDimitry Andric 
7468d75effSDimitry Andric   if (!full_shadow_is_available)
7568d75effSDimitry Andric     full_shadow_is_available =
7668d75effSDimitry Andric         MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
7768d75effSDimitry Andric 
7868d75effSDimitry Andric #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
7968d75effSDimitry Andric     !ASAN_FIXED_MAPPING
8068d75effSDimitry Andric   if (!full_shadow_is_available) {
8168d75effSDimitry Andric     kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
8268d75effSDimitry Andric     kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
8368d75effSDimitry Andric   }
8468d75effSDimitry Andric #endif
8568d75effSDimitry Andric 
8668d75effSDimitry Andric   if (Verbosity()) PrintAddressSpaceLayout();
8768d75effSDimitry Andric 
8868d75effSDimitry Andric   if (full_shadow_is_available) {
8968d75effSDimitry Andric     // mmap the low shadow plus at least one page at the left.
9068d75effSDimitry Andric     if (kLowShadowBeg)
9168d75effSDimitry Andric       ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
9268d75effSDimitry Andric     // mmap the high shadow.
9368d75effSDimitry Andric     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
9468d75effSDimitry Andric     // protect the gap.
9568d75effSDimitry Andric     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
9668d75effSDimitry Andric     CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
9768d75effSDimitry Andric   } else if (kMidMemBeg &&
9868d75effSDimitry Andric              MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
9968d75effSDimitry Andric              MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
10068d75effSDimitry Andric     CHECK(kLowShadowBeg != kLowShadowEnd);
10168d75effSDimitry Andric     // mmap the low shadow plus at least one page at the left.
10268d75effSDimitry Andric     ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
10368d75effSDimitry Andric     // mmap the mid shadow.
10468d75effSDimitry Andric     ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
10568d75effSDimitry Andric     // mmap the high shadow.
10668d75effSDimitry Andric     ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
10768d75effSDimitry Andric     // protect the gaps.
10868d75effSDimitry Andric     ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
10968d75effSDimitry Andric     ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
11068d75effSDimitry Andric     ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
11168d75effSDimitry Andric   } else {
11268d75effSDimitry Andric     Report(
11368d75effSDimitry Andric         "Shadow memory range interleaves with an existing memory mapping. "
11468d75effSDimitry Andric         "ASan cannot proceed correctly. ABORTING.\n");
11568d75effSDimitry Andric     Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
116*349cc55cSDimitry Andric            (void*)shadow_start, (void*)kHighShadowEnd);
11768d75effSDimitry Andric     MaybeReportLinuxPIEBug();
11868d75effSDimitry Andric     DumpProcessMap();
11968d75effSDimitry Andric     Die();
12068d75effSDimitry Andric   }
12168d75effSDimitry Andric }
12268d75effSDimitry Andric 
12368d75effSDimitry Andric }  // namespace __asan
12468d75effSDimitry Andric 
125fe6060f1SDimitry Andric #endif  // !SANITIZER_FUCHSIA
126