brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.0 KiB · f08a7c9 Raw
337 lines · cpp
1//===-- msan_linux.cpp ----------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of MemorySanitizer.10//11// Linux-, NetBSD- and FreeBSD-specific code.12//===----------------------------------------------------------------------===//13 14#include "sanitizer_common/sanitizer_platform.h"15#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD16 17#  include <elf.h>18#  include <link.h>19#  include <pthread.h>20#  include <signal.h>21#  include <stdio.h>22#  include <stdlib.h>23#  if SANITIZER_LINUX24#    include <sys/personality.h>25#  endif26#  include <sys/resource.h>27#  include <sys/time.h>28#  include <unistd.h>29#  include <unwind.h>30 31#  include "msan.h"32#  include "msan_allocator.h"33#  include "msan_chained_origin_depot.h"34#  include "msan_report.h"35#  include "msan_thread.h"36#  include "sanitizer_common/sanitizer_common.h"37#  include "sanitizer_common/sanitizer_procmaps.h"38#  include "sanitizer_common/sanitizer_stackdepot.h"39 40namespace __msan {41 42void ReportMapRange(const char *descr, uptr beg, uptr size) {43  if (size > 0) {44    uptr end = beg + size - 1;45    VPrintf(1, "%s : %p-%p\n", descr, (void *)beg, (void *)end);46  }47}48 49static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {50  if (size > 0) {51    uptr end = beg + size - 1;52    if (!MemoryRangeIsAvailable(beg, end)) {53      if (verbose)54        Printf("FATAL: MemorySanitizer: Shadow range %p-%p is not available.\n",55               (void *)beg, (void *)end);56      return false;57    }58  }59  return true;60}61 62static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {63  if (size > 0) {64    void *addr = MmapFixedNoAccess(beg, size, name);65    if (beg == 0 && addr) {66      // Depending on the kernel configuration, we may not be able to protect67      // the page at address zero.68      uptr gap = 16 * GetPageSizeCached();69      beg += gap;70      size -= gap;71      addr = MmapFixedNoAccess(beg, size, name);72    }73    if ((uptr)addr != beg) {74      uptr end = beg + size - 1;75      Printf(76          "FATAL: MemorySanitizer: Cannot protect memory range %p-%p (%s).\n",77          (void *)beg, (void *)end, name);78      return false;79    }80  }81  return true;82}83 84static void CheckMemoryLayoutSanity() {85  uptr prev_end = 0;86  for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {87    uptr start = kMemoryLayout[i].start;88    uptr end = kMemoryLayout[i].end;89    MappingDesc::Type type = kMemoryLayout[i].type;90    CHECK_LT(start, end);91    CHECK_EQ(prev_end, start);92    CHECK(addr_is_type(start, type));93    CHECK(addr_is_type((start + end) / 2, type));94    CHECK(addr_is_type(end - 1, type));95    if (type == MappingDesc::APP || type == MappingDesc::ALLOCATOR) {96      uptr addr = start;97      CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));98      CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));99      CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));100 101      addr = (start + end) / 2;102      CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));103      CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));104      CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));105 106      addr = end - 1;107      CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));108      CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));109      CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));110    }111    prev_end = end;112  }113}114 115static bool InitShadow(bool init_origins, bool dry_run) {116  // Let user know mapping parameters first.117  VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));118  for (unsigned i = 0; i < kMemoryLayoutSize; ++i)119    VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,120            kMemoryLayout[i].end - 1);121 122  CheckMemoryLayoutSanity();123 124  if (!MEM_IS_APP(&__msan_init)) {125    if (!dry_run)126      Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",127             reinterpret_cast<void *>(&__msan_init));128    return false;129  }130 131  const uptr maxVirtualAddress = GetMaxUserVirtualAddress();132 133  for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {134    uptr start = kMemoryLayout[i].start;135    uptr end = kMemoryLayout[i].end;136    uptr size = end - start;137    MappingDesc::Type type = kMemoryLayout[i].type;138 139    // Check if the segment should be mapped based on platform constraints.140    if (start >= maxVirtualAddress)141      continue;142 143    bool map = type == MappingDesc::SHADOW ||144               (init_origins && type == MappingDesc::ORIGIN);145    bool protect = type == MappingDesc::INVALID ||146                   (!init_origins && type == MappingDesc::ORIGIN);147    CHECK(!(map && protect));148    if (!map && !protect) {149      CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);150 151      if (dry_run && type == MappingDesc::ALLOCATOR &&152          !CheckMemoryRangeAvailability(start, size, !dry_run))153        return false;154    }155    if (map) {156      if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))157        return false;158      if (!dry_run &&159          !MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))160        return false;161      if (!dry_run && common_flags()->use_madv_dontdump)162        DontDumpShadowMemory(start, size);163    }164    if (protect) {165      if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))166        return false;167      if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))168        return false;169    }170  }171 172  return true;173}174 175bool InitShadowWithReExec(bool init_origins) {176  // Start with dry run: check layout is ok, but don't print warnings because177  // warning messages will cause tests to fail (even if we successfully re-exec178  // after the warning).179  bool success = InitShadow(init_origins, true);180  if (!success) {181#  if SANITIZER_LINUX182    // Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.183    int old_personality = personality(0xffffffff);184    bool aslr_on =185        (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);186 187    if (aslr_on) {188      VReport(1,189              "WARNING: MemorySanitizer: memory layout is incompatible, "190              "possibly due to high-entropy ASLR.\n"191              "Re-execing with fixed virtual address space.\n"192              "N.B. reducing ASLR entropy is preferable.\n");193 194      if (personality(old_personality | ADDR_NO_RANDOMIZE) == -1) {195        Printf(196            "FATAL: MemorySanitizer: unable to disable ASLR (perhaps "197            "sandboxing is enabled?).\n");198        Printf("FATAL: Please rerun without sandboxing and/or ASLR.\n");199        Die();200      }201 202      ReExec();203    }204#  endif205  }206 207  // The earlier dry run didn't actually map or protect anything. Run again in208  // non-dry run mode.209  return success && InitShadow(init_origins, false);210}211 212static void MsanAtExit(void) {213  if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))214    ReportStats();215  if (msan_report_count > 0) {216    ReportAtExitStatistics();217    if (common_flags()->exitcode)218      internal__exit(common_flags()->exitcode);219  }220}221 222void InstallAtExitHandler() {223  atexit(MsanAtExit);224}225 226// ---------------------- TSD ---------------- {{{1227 228#if SANITIZER_NETBSD229// Thread Static Data cannot be used in early init on NetBSD.230// Reuse the MSan TSD API for compatibility with existing code231// with an alternative implementation.232 233static void (*tsd_destructor)(void *tsd) = nullptr;234 235struct tsd_key {236  tsd_key() : key(nullptr) {}237  ~tsd_key() {238    CHECK(tsd_destructor);239    if (key)240      (*tsd_destructor)(key);241  }242  MsanThread *key;243};244 245static thread_local struct tsd_key key;246 247void MsanTSDInit(void (*destructor)(void *tsd)) {248  CHECK(!tsd_destructor);249  tsd_destructor = destructor;250}251 252MsanThread *GetCurrentThread() {253  CHECK(tsd_destructor);254  return key.key;255}256 257void SetCurrentThread(MsanThread *tsd) {258  CHECK(tsd_destructor);259  CHECK(tsd);260  CHECK(!key.key);261  key.key = tsd;262}263 264void MsanTSDDtor(void *tsd) {265  CHECK(tsd_destructor);266  CHECK_EQ(key.key, tsd);267  key.key = nullptr;268  // Make sure that signal handler can not see a stale current thread pointer.269  atomic_signal_fence(memory_order_seq_cst);270  MsanThread::TSDDtor(tsd);271}272#else273static pthread_key_t tsd_key;274static bool tsd_key_inited = false;275 276void MsanTSDInit(void (*destructor)(void *tsd)) {277  CHECK(!tsd_key_inited);278  tsd_key_inited = true;279  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));280}281 282static THREADLOCAL MsanThread* msan_current_thread;283 284MsanThread *GetCurrentThread() {285  return msan_current_thread;286}287 288void SetCurrentThread(MsanThread *t) {289  // Make sure we do not reset the current MsanThread.290  CHECK_EQ(0, msan_current_thread);291  msan_current_thread = t;292  // Make sure that MsanTSDDtor gets called at the end.293  CHECK(tsd_key_inited);294  pthread_setspecific(tsd_key, (void *)t);295}296 297void MsanTSDDtor(void *tsd) {298  MsanThread *t = (MsanThread*)tsd;299  if (t->destructor_iterations_ > 1) {300    t->destructor_iterations_--;301    CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));302    return;303  }304  ScopedBlockSignals block(nullptr);305  msan_current_thread = nullptr;306  // Make sure that signal handler can not see a stale current thread pointer.307  atomic_signal_fence(memory_order_seq_cst);308  MsanThread::TSDDtor(tsd);309}310#  endif311 312static void BeforeFork() {313  VReport(2, "BeforeFork tid: %llu\n", GetTid());314  // Usually we lock ThreadRegistry, but msan does not have one.315  LockAllocator();316  StackDepotLockBeforeFork();317  ChainedOriginDepotBeforeFork();318}319 320static void AfterFork(bool fork_child) {321  ChainedOriginDepotAfterFork(fork_child);322  StackDepotUnlockAfterFork(fork_child);323  UnlockAllocator();324  // Usually we unlock ThreadRegistry, but msan does not have one.325  VReport(2, "AfterFork tid: %llu\n", GetTid());326}327 328void InstallAtForkHandler() {329  pthread_atfork(330      &BeforeFork, []() { AfterFork(/* fork_child= */ false); },331      []() { AfterFork(/* fork_child= */ true); });332}333 334} // namespace __msan335 336#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD337