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
27void 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
35namespace gwp_asan {
36void *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
44void 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
51void 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
58void 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
69size_t GuardedPoolAllocator::getPlatformPageSize() {
70  return sysconf(_SC_PAGESIZE);
71}
72
73void 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