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
28namespace {
29void 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
38namespace gwp_asan {
39
40void GuardedPoolAllocator::initPRNG() {
41  getThreadLocals()->RandomState =
42      static_cast<uint32_t>(time(nullptr) + getThreadID());
43}
44
45void *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
54void 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
61void *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
70void GuardedPoolAllocator::unreserveGuardedPool() {
71  unmap(reinterpret_cast<void *>(State.GuardedPagePool),
72        State.GuardedPagePoolEnd - State.GuardedPagePool);
73}
74
75void 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
83void 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
96size_t GuardedPoolAllocator::getPlatformPageSize() {
97  return sysconf(_SC_PAGESIZE);
98}
99
100void GuardedPoolAllocator::installAtFork() {
101  static bool AtForkInstalled = false;
102  if (AtForkInstalled)
103    return;
104  AtForkInstalled = true;
105  auto Disable = []() {
106    if (auto *S = getSingleton())
107      S->disable();
108  };
109  auto Enable = []() {
110    if (auto *S = getSingleton())
111      S->enable();
112  };
113  pthread_atfork(Disable, Enable, Enable);
114}
115} // namespace gwp_asan
116