1 //===-- guarded_pool_allocator_posix.cpp ------------------------*- C++ -*-===// 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 #include "gwp_asan/guarded_pool_allocator.h" 10 11 #include <stdlib.h> 12 #include <errno.h> 13 #include <signal.h> 14 #include <sys/mman.h> 15 #include <sys/syscall.h> 16 #include <sys/types.h> 17 #include <unistd.h> 18 19 namespace gwp_asan { 20 21 void *GuardedPoolAllocator::mapMemory(size_t Size) const { 22 void *Ptr = 23 mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 24 25 if (Ptr == MAP_FAILED) { 26 Printf("Failed to map guarded pool allocator memory, errno: %d\n", errno); 27 Printf(" mmap(nullptr, %zu, ...) failed.\n", Size); 28 exit(EXIT_FAILURE); 29 } 30 return Ptr; 31 } 32 33 void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size) const { 34 if (mprotect(Ptr, Size, PROT_READ | PROT_WRITE) != 0) { 35 Printf("Failed to set guarded pool allocator memory at as RW, errno: %d\n", 36 errno); 37 Printf(" mprotect(%p, %zu, RW) failed.\n", Ptr, Size); 38 exit(EXIT_FAILURE); 39 } 40 } 41 42 void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size) const { 43 // mmap() a PROT_NONE page over the address to release it to the system, if 44 // we used mprotect() here the system would count pages in the quarantine 45 // against the RSS. 46 if (mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 47 0) == MAP_FAILED) { 48 Printf("Failed to set guarded pool allocator memory as inaccessible, " 49 "errno: %d\n", 50 errno); 51 Printf(" mmap(%p, %zu, NONE, ...) failed.\n", Ptr, Size); 52 exit(EXIT_FAILURE); 53 } 54 } 55 56 size_t GuardedPoolAllocator::getPlatformPageSize() { 57 return sysconf(_SC_PAGESIZE); 58 } 59 60 struct sigaction PreviousHandler; 61 62 static void sigSegvHandler(int sig, siginfo_t *info, void *ucontext) { 63 gwp_asan::GuardedPoolAllocator::reportError( 64 reinterpret_cast<uintptr_t>(info->si_addr)); 65 66 // Process any previous handlers. 67 if (PreviousHandler.sa_flags & SA_SIGINFO) { 68 PreviousHandler.sa_sigaction(sig, info, ucontext); 69 } else if (PreviousHandler.sa_handler == SIG_IGN || 70 PreviousHandler.sa_handler == SIG_DFL) { 71 // If the previous handler was the default handler, or was ignoring this 72 // signal, install the default handler and re-raise the signal in order to 73 // get a core dump and terminate this process. 74 signal(SIGSEGV, SIG_DFL); 75 raise(SIGSEGV); 76 } else { 77 PreviousHandler.sa_handler(sig); 78 } 79 } 80 81 void GuardedPoolAllocator::installSignalHandlers() { 82 struct sigaction Action; 83 Action.sa_sigaction = sigSegvHandler; 84 Action.sa_flags = SA_SIGINFO; 85 sigaction(SIGSEGV, &Action, &PreviousHandler); 86 } 87 88 uint64_t GuardedPoolAllocator::getThreadID() { 89 #ifdef SYS_gettid 90 return syscall(SYS_gettid); 91 #else 92 return kInvalidThreadID; 93 #endif 94 } 95 96 } // namespace gwp_asan 97