Summary: This refactors some common support related to shadow memory setup from asan and hwasan into sanitizer_common. This should not only reduce code duplication but also make these facilities available for new compiler-rt uses (e.g. heap profiling). In most cases the separate copies of the code were either identical, or at least functionally identical. A few notes: In ProtectGap, the asan version checked the address against an upper bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as it isn't clear why that code should not do the same check. If it shouldn't, I can remove this and guard this check so that it only happens for asan. In asan's InitializeShadowMemory, in the dynamic shadow case it was setting __asan_shadow_memory_dynamic_address to 0 (which then sets both macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling FindDynamicShadowStart(). AFAICT this is only needed because FindDynamicShadowStart utilizes kHighShadowEnd to get the shadow size, and kHighShadowEnd is a macro invoking MEM_TO_SHADOW(kHighMemEnd) which in turn invokes: (((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET)) I.e. it computes the shadow space needed by kHighMemEnd (the shift), and adds the offset. Since we only want the shadow space here, the earlier setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address accomplishes this. In the hwasan version, it simply gets the shadow space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just does the shift. I've simplified the asan handling to do the same thing, and therefore was able to remove the setting of the SHADOW_OFFSET via __asan_shadow_memory_dynamic_address to 0. Reviewers: vitalybuka, kcc, eugenis Subscribers: dberris, #sanitizers, llvm-commits, davidxl Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D83247
127 lines
4.0 KiB
C++
127 lines
4.0 KiB
C++
//===-- hwasan_dynamic_shadow.cpp -------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// This file is a part of HWAddressSanitizer. It reserves dynamic shadow memory
|
|
/// region and handles ifunc resolver case, when necessary.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "hwasan.h"
|
|
#include "hwasan_dynamic_shadow.h"
|
|
#include "hwasan_mapping.h"
|
|
#include "sanitizer_common/sanitizer_common.h"
|
|
#include "sanitizer_common/sanitizer_posix.h"
|
|
|
|
#include <elf.h>
|
|
#include <link.h>
|
|
|
|
// The code in this file needs to run in an unrelocated binary. It should not
|
|
// access any external symbol, including its own non-hidden globals.
|
|
|
|
#if SANITIZER_ANDROID
|
|
extern "C" {
|
|
|
|
INTERFACE_ATTRIBUTE void __hwasan_shadow();
|
|
decltype(__hwasan_shadow)* __hwasan_premap_shadow();
|
|
|
|
} // extern "C"
|
|
|
|
namespace __hwasan {
|
|
|
|
// Conservative upper limit.
|
|
static uptr PremapShadowSize() {
|
|
return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale,
|
|
GetMmapGranularity());
|
|
}
|
|
|
|
static uptr PremapShadow() {
|
|
return MapDynamicShadow(PremapShadowSize(), kShadowScale,
|
|
kShadowBaseAlignment, kHighMemEnd);
|
|
}
|
|
|
|
static bool IsPremapShadowAvailable() {
|
|
const uptr shadow = reinterpret_cast<uptr>(&__hwasan_shadow);
|
|
const uptr resolver = reinterpret_cast<uptr>(&__hwasan_premap_shadow);
|
|
// shadow == resolver is how Android KitKat and older handles ifunc.
|
|
// shadow == 0 just in case.
|
|
return shadow != 0 && shadow != resolver;
|
|
}
|
|
|
|
static uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
|
|
const uptr granularity = GetMmapGranularity();
|
|
const uptr shadow_start = reinterpret_cast<uptr>(&__hwasan_shadow);
|
|
const uptr premap_shadow_size = PremapShadowSize();
|
|
const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
|
|
|
|
// We may have mapped too much. Release extra memory.
|
|
UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
|
|
return shadow_start;
|
|
}
|
|
|
|
} // namespace __hwasan
|
|
|
|
extern "C" {
|
|
|
|
decltype(__hwasan_shadow)* __hwasan_premap_shadow() {
|
|
// The resolver might be called multiple times. Map the shadow just once.
|
|
static __sanitizer::uptr shadow = 0;
|
|
if (!shadow)
|
|
shadow = __hwasan::PremapShadow();
|
|
return reinterpret_cast<decltype(__hwasan_shadow)*>(shadow);
|
|
}
|
|
|
|
// __hwasan_shadow is a "function" that has the same address as the first byte
|
|
// of the shadow mapping.
|
|
INTERFACE_ATTRIBUTE __attribute__((ifunc("__hwasan_premap_shadow")))
|
|
void __hwasan_shadow();
|
|
|
|
extern __attribute((weak, visibility("hidden"))) ElfW(Rela) __rela_iplt_start[],
|
|
__rela_iplt_end[];
|
|
|
|
} // extern "C"
|
|
|
|
namespace __hwasan {
|
|
|
|
void InitShadowGOT() {
|
|
// Call the ifunc resolver for __hwasan_shadow and fill in its GOT entry. This
|
|
// needs to be done before other ifunc resolvers (which are handled by libc)
|
|
// because a resolver might read __hwasan_shadow.
|
|
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
|
|
for (ElfW(Rela) *r = __rela_iplt_start; r != __rela_iplt_end; ++r) {
|
|
ElfW(Addr)* offset = reinterpret_cast<ElfW(Addr)*>(r->r_offset);
|
|
ElfW(Addr) resolver = r->r_addend;
|
|
if (resolver == reinterpret_cast<ElfW(Addr)>(&__hwasan_premap_shadow)) {
|
|
*offset = reinterpret_cast<ifunc_resolver_t>(resolver)();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
|
|
if (IsPremapShadowAvailable())
|
|
return FindPremappedShadowStart(shadow_size_bytes);
|
|
return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
|
|
kHighMemEnd);
|
|
}
|
|
|
|
} // namespace __hwasan
|
|
#else
|
|
namespace __hwasan {
|
|
|
|
void InitShadowGOT() {}
|
|
|
|
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
|
|
return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
|
|
kHighMemEnd);
|
|
}
|
|
|
|
} // namespace __hwasan
|
|
|
|
#endif // SANITIZER_ANDROID
|