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