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