xref: /aosp_15_r20/external/gwp_asan/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp (revision b302aa5039729da396909ef03e815160dab4448c)
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 {
MaybeSetMappingName(void * Mapping,size_t Size,const char * Name)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 
initPRNG()41 void GuardedPoolAllocator::initPRNG() {
42   getThreadLocals()->RandomState =
43       static_cast<uint32_t>(time(nullptr) + getThreadID());
44 }
45 
map(size_t Size,const char * Name) const46 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 
unmap(void * Ptr,size_t Size) const56 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 
reserveGuardedPool(size_t Size)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 
unreserveGuardedPool()73 void GuardedPoolAllocator::unreserveGuardedPool() {
74   unmap(reinterpret_cast<void *>(State.GuardedPagePool),
75         State.GuardedPagePoolEnd - State.GuardedPagePool);
76 }
77 
allocateInGuardedPool(void * Ptr,size_t Size) const78 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 
deallocateInGuardedPool(void * Ptr,size_t Size) const87 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 
getPlatformPageSize()101 size_t GuardedPoolAllocator::getPlatformPageSize() {
102   return sysconf(_SC_PAGESIZE);
103 }
104 
installAtFork()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