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 #include "gwp_asan/utilities.h"
11 
12 #include <assert.h>
13 #include <errno.h>
14 #include <signal.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/mman.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20 
21 #ifdef ANDROID
22 #include <sys/prctl.h>
23 #define PR_SET_VMA 0x53564d41
24 #define PR_SET_VMA_ANON_NAME 0
25 #endif // ANDROID
26 
27 void MaybeSetMappingName(void *Mapping, size_t Size, const char *Name) {
28 #ifdef ANDROID
29   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, Mapping, Size, Name);
30 #endif // ANDROID
31   // Anonymous mapping names are only supported on Android.
32   return;
33 }
34 
35 namespace gwp_asan {
36 void *GuardedPoolAllocator::mapMemory(size_t Size, const char *Name) const {
37   void *Ptr =
38       mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
39   Check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory");
40   MaybeSetMappingName(Ptr, Size, Name);
41   return Ptr;
42 }
43 
44 void GuardedPoolAllocator::unmapMemory(void *Ptr, size_t Size,
45                                        const char *Name) const {
46   Check(munmap(Ptr, Size) == 0,
47         "Failed to unmap guarded pool allocator memory.");
48   MaybeSetMappingName(Ptr, Size, Name);
49 }
50 
51 void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size,
52                                          const char *Name) const {
53   Check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0,
54         "Failed to set guarded pool allocator memory at as RW.");
55   MaybeSetMappingName(Ptr, Size, Name);
56 }
57 
58 void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size,
59                                             const char *Name) const {
60   // mmap() a PROT_NONE page over the address to release it to the system, if
61   // we used mprotect() here the system would count pages in the quarantine
62   // against the RSS.
63   Check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1,
64              0) != MAP_FAILED,
65         "Failed to set guarded pool allocator memory as inaccessible.");
66   MaybeSetMappingName(Ptr, Size, Name);
67 }
68 
69 size_t GuardedPoolAllocator::getPlatformPageSize() {
70   return sysconf(_SC_PAGESIZE);
71 }
72 
73 void GuardedPoolAllocator::installAtFork() {
74   auto Disable = []() {
75     if (auto *S = getSingleton())
76       S->disable();
77   };
78   auto Enable = []() {
79     if (auto *S = getSingleton())
80       S->enable();
81   };
82   pthread_atfork(Disable, Enable, Enable);
83 }
84 
85 } // namespace gwp_asan
86