diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /compiler-rt/lib/gwp_asan/platform_specific | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'compiler-rt/lib/gwp_asan/platform_specific')
3 files changed, 163 insertions, 60 deletions
diff --git a/compiler-rt/lib/gwp_asan/platform_specific/common_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/common_posix.cpp new file mode 100644 index 000000000000..e44e6299eeac --- /dev/null +++ b/compiler-rt/lib/gwp_asan/platform_specific/common_posix.cpp @@ -0,0 +1,24 @@ +//===-- common_posix.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 +// +//===----------------------------------------------------------------------===// + +#include "gwp_asan/common.h" + +#include <sys/syscall.h> +#include <unistd.h> + +namespace gwp_asan { + +uint64_t getThreadID() { +#ifdef SYS_gettid + return syscall(SYS_gettid); +#else + return kInvalidThreadID; +#endif +} + +} // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp index 8bc0aefeec44..a8767a4cb808 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp @@ -7,90 +7,79 @@ //===----------------------------------------------------------------------===// #include "gwp_asan/guarded_pool_allocator.h" +#include "gwp_asan/utilities.h" -#include <stdlib.h> +#include <assert.h> #include <errno.h> #include <signal.h> +#include <stdlib.h> +#include <string.h> #include <sys/mman.h> -#include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> -namespace gwp_asan { +#ifdef ANDROID +#include <sys/prctl.h> +#define PR_SET_VMA 0x53564d41 +#define PR_SET_VMA_ANON_NAME 0 +#endif // ANDROID + +void MaybeSetMappingName(void *Mapping, size_t Size, const char *Name) { +#ifdef ANDROID + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Mapping, Size, Name); +#endif // ANDROID + // Anonymous mapping names are only supported on Android. + return; +} -void *GuardedPoolAllocator::mapMemory(size_t Size) const { +namespace gwp_asan { +void *GuardedPoolAllocator::mapMemory(size_t Size, const char *Name) const { void *Ptr = mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - - if (Ptr == MAP_FAILED) { - Printf("Failed to map guarded pool allocator memory, errno: %d\n", errno); - Printf(" mmap(nullptr, %zu, ...) failed.\n", Size); - exit(EXIT_FAILURE); - } + Check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory"); + MaybeSetMappingName(Ptr, Size, Name); return Ptr; } -void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size) const { - if (mprotect(Ptr, Size, PROT_READ | PROT_WRITE) != 0) { - Printf("Failed to set guarded pool allocator memory at as RW, errno: %d\n", - errno); - Printf(" mprotect(%p, %zu, RW) failed.\n", Ptr, Size); - exit(EXIT_FAILURE); - } +void GuardedPoolAllocator::unmapMemory(void *Ptr, size_t Size, + const char *Name) const { + Check(munmap(Ptr, Size) == 0, + "Failed to unmap guarded pool allocator memory."); + MaybeSetMappingName(Ptr, Size, Name); } -void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size) const { +void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size, + const char *Name) const { + Check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, + "Failed to set guarded pool allocator memory at as RW."); + MaybeSetMappingName(Ptr, Size, Name); +} + +void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size, + const char *Name) const { // mmap() a PROT_NONE page over the address to release it to the system, if // we used mprotect() here the system would count pages in the quarantine // against the RSS. - if (mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, - 0) == MAP_FAILED) { - Printf("Failed to set guarded pool allocator memory as inaccessible, " - "errno: %d\n", - errno); - Printf(" mmap(%p, %zu, NONE, ...) failed.\n", Ptr, Size); - exit(EXIT_FAILURE); - } + Check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, + 0) != MAP_FAILED, + "Failed to set guarded pool allocator memory as inaccessible."); + MaybeSetMappingName(Ptr, Size, Name); } size_t GuardedPoolAllocator::getPlatformPageSize() { return sysconf(_SC_PAGESIZE); } -struct sigaction PreviousHandler; - -static void sigSegvHandler(int sig, siginfo_t *info, void *ucontext) { - gwp_asan::GuardedPoolAllocator::reportError( - reinterpret_cast<uintptr_t>(info->si_addr)); - - // Process any previous handlers. - if (PreviousHandler.sa_flags & SA_SIGINFO) { - PreviousHandler.sa_sigaction(sig, info, ucontext); - } else if (PreviousHandler.sa_handler == SIG_IGN || - PreviousHandler.sa_handler == SIG_DFL) { - // If the previous handler was the default handler, or was ignoring this - // signal, install the default handler and re-raise the signal in order to - // get a core dump and terminate this process. - signal(SIGSEGV, SIG_DFL); - raise(SIGSEGV); - } else { - PreviousHandler.sa_handler(sig); - } -} - -void GuardedPoolAllocator::installSignalHandlers() { - struct sigaction Action; - Action.sa_sigaction = sigSegvHandler; - Action.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &Action, &PreviousHandler); -} - -uint64_t GuardedPoolAllocator::getThreadID() { -#ifdef SYS_gettid - return syscall(SYS_gettid); -#else - return kInvalidThreadID; -#endif +void GuardedPoolAllocator::installAtFork() { + auto Disable = []() { + if (auto *S = getSingleton()) + S->disable(); + }; + auto Enable = []() { + if (auto *S = getSingleton()) + S->enable(); + }; + pthread_atfork(Disable, Enable, Enable); } } // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp new file mode 100644 index 000000000000..0e6059896702 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp @@ -0,0 +1,90 @@ +//===-- utilities_posix.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 +// +//===----------------------------------------------------------------------===// + +#include "gwp_asan/definitions.h" +#include "gwp_asan/utilities.h" + +#include <assert.h> + +#ifdef __BIONIC__ +#include <stdlib.h> +extern "C" GWP_ASAN_WEAK void android_set_abort_message(const char *); +#else // __BIONIC__ +#include <stdio.h> +#endif + +namespace gwp_asan { + +#ifdef __BIONIC__ +void Check(bool Condition, const char *Message) { + if (Condition) + return; + if (&android_set_abort_message != nullptr) + android_set_abort_message(Message); + abort(); +} +#else // __BIONIC__ +void Check(bool Condition, const char *Message) { + if (Condition) + return; + fprintf(stderr, "%s", Message); + __builtin_trap(); +} +#endif // __BIONIC__ + +// See `bionic/tests/malloc_test.cpp` in the Android source for documentation +// regarding their alignment guarantees. We always round up to the closest +// 8-byte window. As GWP-ASan's malloc(X) can always get exactly an X-sized +// allocation, an allocation that rounds up to 16-bytes will always be given a +// 16-byte aligned allocation. +static size_t alignBionic(size_t RealAllocationSize) { + if (RealAllocationSize % 8 == 0) + return RealAllocationSize; + return RealAllocationSize + 8 - (RealAllocationSize % 8); +} + +static size_t alignPowerOfTwo(size_t RealAllocationSize) { + if (RealAllocationSize <= 2) + return RealAllocationSize; + if (RealAllocationSize <= 4) + return 4; + if (RealAllocationSize <= 8) + return 8; + if (RealAllocationSize % 16 == 0) + return RealAllocationSize; + return RealAllocationSize + 16 - (RealAllocationSize % 16); +} + +#ifdef __BIONIC__ +static constexpr AlignmentStrategy PlatformDefaultAlignment = + AlignmentStrategy::BIONIC; +#else // __BIONIC__ +static constexpr AlignmentStrategy PlatformDefaultAlignment = + AlignmentStrategy::POWER_OF_TWO; +#endif // __BIONIC__ + +size_t rightAlignedAllocationSize(size_t RealAllocationSize, + AlignmentStrategy Align) { + assert(RealAllocationSize > 0); + if (Align == AlignmentStrategy::DEFAULT) + Align = PlatformDefaultAlignment; + + switch (Align) { + case AlignmentStrategy::BIONIC: + return alignBionic(RealAllocationSize); + case AlignmentStrategy::POWER_OF_TWO: + return alignPowerOfTwo(RealAllocationSize); + case AlignmentStrategy::PERFECT: + return RealAllocationSize; + case AlignmentStrategy::DEFAULT: + __builtin_unreachable(); + } + __builtin_unreachable(); +} + +} // namespace gwp_asan |