reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
//===-- guarded_pool_allocator_posix.cpp ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "gwp_asan/guarded_pool_allocator.h"

#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

namespace gwp_asan {

void *GuardedPoolAllocator::mapMemory(size_t Size) const {
  void *Ptr =
      mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

  if (Ptr == MAP_FAILED) {
    Printf("Failed to map guarded pool allocator memory, errno: %d\n", errno);
    Printf("  mmap(nullptr, %zu, ...) failed.\n", Size);
    exit(EXIT_FAILURE);
  }
  return Ptr;
}

void GuardedPoolAllocator::markReadWrite(void *Ptr, size_t Size) const {
  if (mprotect(Ptr, Size, PROT_READ | PROT_WRITE) != 0) {
    Printf("Failed to set guarded pool allocator memory at as RW, errno: %d\n",
           errno);
    Printf("  mprotect(%p, %zu, RW) failed.\n", Ptr, Size);
    exit(EXIT_FAILURE);
  }
}

void GuardedPoolAllocator::markInaccessible(void *Ptr, size_t Size) const {
  // mmap() a PROT_NONE page over the address to release it to the system, if
  // we used mprotect() here the system would count pages in the quarantine
  // against the RSS.
  if (mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1,
           0) == MAP_FAILED) {
    Printf("Failed to set guarded pool allocator memory as inaccessible, "
           "errno: %d\n",
           errno);
    Printf("  mmap(%p, %zu, NONE, ...) failed.\n", Ptr, Size);
    exit(EXIT_FAILURE);
  }
}

size_t GuardedPoolAllocator::getPlatformPageSize() {
  return sysconf(_SC_PAGESIZE);
}

struct sigaction PreviousHandler;

static void sigSegvHandler(int sig, siginfo_t *info, void *ucontext) {
  gwp_asan::GuardedPoolAllocator::reportError(
      reinterpret_cast<uintptr_t>(info->si_addr));

  // Process any previous handlers.
  if (PreviousHandler.sa_flags & SA_SIGINFO) {
    PreviousHandler.sa_sigaction(sig, info, ucontext);
  } else if (PreviousHandler.sa_handler == SIG_IGN ||
             PreviousHandler.sa_handler == SIG_DFL) {
    // If the previous handler was the default handler, or was ignoring this
    // signal, install the default handler and re-raise the signal in order to
    // get a core dump and terminate this process.
    signal(SIGSEGV, SIG_DFL);
    raise(SIGSEGV);
  } else {
    PreviousHandler.sa_handler(sig);
  }
}

void GuardedPoolAllocator::installSignalHandlers() {
  struct sigaction Action;
  Action.sa_sigaction = sigSegvHandler;
  Action.sa_flags = SA_SIGINFO;
  sigaction(SIGSEGV, &Action, &PreviousHandler);
}

uint64_t GuardedPoolAllocator::getThreadID() {
#ifdef SYS_gettid
  return syscall(SYS_gettid);
#else
  return kInvalidThreadID;
#endif
}

} // namespace gwp_asan