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/common.h" 10 #include "gwp_asan/guarded_pool_allocator.h" 11 #include "gwp_asan/platform_specific/guarded_pool_allocator_tls.h" 12 #include "gwp_asan/utilities.h" 13 14 #include <assert.h> 15 #include <errno.h> 16 #include <pthread.h> 17 #include <stdint.h> 18 #include <stdlib.h> 19 #include <sys/mman.h> 20 #include <time.h> 21 #include <unistd.h> 22 23 #ifdef ANDROID 24 #include <sys/prctl.h> 25 #define PR_SET_VMA 0x53564d41 26 #define PR_SET_VMA_ANON_NAME 0 27 #endif // ANDROID 28 29 namespace { 30 void MaybeSetMappingName(void *Mapping, size_t Size, const char *Name) { 31 #ifdef ANDROID 32 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Mapping, Size, Name); 33 #endif // ANDROID 34 // Anonymous mapping names are only supported on Android. 35 return; 36 } 37 } // anonymous namespace 38 39 namespace gwp_asan { 40 41 void GuardedPoolAllocator::initPRNG() { 42 getThreadLocals()->RandomState = 43 static_cast<uint32_t>(time(nullptr) + getThreadID()); 44 } 45 46 void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { 47 assert((Size % State.PageSize) == 0); 48 void *Ptr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, 49 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 50 checkWithErrorCode(Ptr != MAP_FAILED, 51 "Failed to map guarded pool allocator memory", errno); 52 MaybeSetMappingName(Ptr, Size, Name); 53 return Ptr; 54 } 55 56 void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { 57 assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0); 58 assert((Size % State.PageSize) == 0); 59 checkWithErrorCode(munmap(Ptr, Size) == 0, 60 "Failed to unmap guarded pool allocator memory.", errno); 61 } 62 63 void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { 64 assert((Size % State.PageSize) == 0); 65 void *Ptr = 66 mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 67 checkWithErrorCode(Ptr != MAP_FAILED, 68 "Failed to reserve guarded pool allocator memory", errno); 69 MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); 70 return Ptr; 71 } 72 73 void GuardedPoolAllocator::unreserveGuardedPool() { 74 unmap(reinterpret_cast<void *>(State.GuardedPagePool), 75 State.GuardedPagePoolEnd - State.GuardedPagePool); 76 } 77 78 void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { 79 assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0); 80 assert((Size % State.PageSize) == 0); 81 checkWithErrorCode(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, 82 "Failed to allocate in guarded pool allocator memory", 83 errno); 84 MaybeSetMappingName(Ptr, Size, kGwpAsanAliveSlotName); 85 } 86 87 void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, 88 size_t Size) const { 89 assert((reinterpret_cast<uintptr_t>(Ptr) % State.PageSize) == 0); 90 assert((Size % State.PageSize) == 0); 91 // mmap() a PROT_NONE page over the address to release it to the system, if 92 // we used mprotect() here the system would count pages in the quarantine 93 // against the RSS. 94 checkWithErrorCode( 95 mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 96 0) != MAP_FAILED, 97 "Failed to deallocate in guarded pool allocator memory", errno); 98 MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); 99 } 100 101 size_t GuardedPoolAllocator::getPlatformPageSize() { 102 return sysconf(_SC_PAGESIZE); 103 } 104 105 void GuardedPoolAllocator::installAtFork() { 106 static bool AtForkInstalled = false; 107 if (AtForkInstalled) 108 return; 109 AtForkInstalled = true; 110 auto Disable = []() { 111 if (auto *S = getSingleton()) 112 S->disable(); 113 }; 114 auto Enable = []() { 115 if (auto *S = getSingleton()) 116 S->enable(); 117 }; 118 pthread_atfork(Disable, Enable, Enable); 119 } 120 } // namespace gwp_asan 121