Path: blob/main/contrib/llvm-project/compiler-rt/lib/msan/msan_linux.cpp
35262 views
//===-- msan_linux.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of MemorySanitizer.9//10// Linux-, NetBSD- and FreeBSD-specific code.11//===----------------------------------------------------------------------===//1213#include "sanitizer_common/sanitizer_platform.h"14#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD1516# include <elf.h>17# include <link.h>18# include <pthread.h>19# include <signal.h>20# include <stdio.h>21# include <stdlib.h>22# if SANITIZER_LINUX23# include <sys/personality.h>24# endif25# include <sys/resource.h>26# include <sys/time.h>27# include <unistd.h>28# include <unwind.h>2930# include "msan.h"31# include "msan_allocator.h"32# include "msan_chained_origin_depot.h"33# include "msan_report.h"34# include "msan_thread.h"35# include "sanitizer_common/sanitizer_common.h"36# include "sanitizer_common/sanitizer_procmaps.h"37# include "sanitizer_common/sanitizer_stackdepot.h"3839namespace __msan {4041void ReportMapRange(const char *descr, uptr beg, uptr size) {42if (size > 0) {43uptr end = beg + size - 1;44VPrintf(1, "%s : %p-%p\n", descr, (void *)beg, (void *)end);45}46}4748static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {49if (size > 0) {50uptr end = beg + size - 1;51if (!MemoryRangeIsAvailable(beg, end)) {52if (verbose)53Printf("FATAL: MemorySanitizer: Shadow range %p-%p is not available.\n",54(void *)beg, (void *)end);55return false;56}57}58return true;59}6061static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {62if (size > 0) {63void *addr = MmapFixedNoAccess(beg, size, name);64if (beg == 0 && addr) {65// Depending on the kernel configuration, we may not be able to protect66// the page at address zero.67uptr gap = 16 * GetPageSizeCached();68beg += gap;69size -= gap;70addr = MmapFixedNoAccess(beg, size, name);71}72if ((uptr)addr != beg) {73uptr end = beg + size - 1;74Printf(75"FATAL: MemorySanitizer: Cannot protect memory range %p-%p (%s).\n",76(void *)beg, (void *)end, name);77return false;78}79}80return true;81}8283static void CheckMemoryLayoutSanity() {84uptr prev_end = 0;85for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {86uptr start = kMemoryLayout[i].start;87uptr end = kMemoryLayout[i].end;88MappingDesc::Type type = kMemoryLayout[i].type;89CHECK_LT(start, end);90CHECK_EQ(prev_end, start);91CHECK(addr_is_type(start, type));92CHECK(addr_is_type((start + end) / 2, type));93CHECK(addr_is_type(end - 1, type));94if (type == MappingDesc::APP || type == MappingDesc::ALLOCATOR) {95uptr addr = start;96CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));97CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));98CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));99100addr = (start + end) / 2;101CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));102CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));103CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));104105addr = end - 1;106CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));107CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));108CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));109}110prev_end = end;111}112}113114static bool InitShadow(bool init_origins, bool dry_run) {115// Let user know mapping parameters first.116VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));117for (unsigned i = 0; i < kMemoryLayoutSize; ++i)118VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,119kMemoryLayout[i].end - 1);120121CheckMemoryLayoutSanity();122123if (!MEM_IS_APP(&__msan_init)) {124if (!dry_run)125Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",126reinterpret_cast<void *>(&__msan_init));127return false;128}129130const uptr maxVirtualAddress = GetMaxUserVirtualAddress();131132for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {133uptr start = kMemoryLayout[i].start;134uptr end = kMemoryLayout[i].end;135uptr size = end - start;136MappingDesc::Type type = kMemoryLayout[i].type;137138// Check if the segment should be mapped based on platform constraints.139if (start >= maxVirtualAddress)140continue;141142bool map = type == MappingDesc::SHADOW ||143(init_origins && type == MappingDesc::ORIGIN);144bool protect = type == MappingDesc::INVALID ||145(!init_origins && type == MappingDesc::ORIGIN);146CHECK(!(map && protect));147if (!map && !protect) {148CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);149150if (dry_run && type == MappingDesc::ALLOCATOR &&151!CheckMemoryRangeAvailability(start, size, !dry_run))152return false;153}154if (map) {155if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))156return false;157if (!dry_run &&158!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))159return false;160if (!dry_run && common_flags()->use_madv_dontdump)161DontDumpShadowMemory(start, size);162}163if (protect) {164if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))165return false;166if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))167return false;168}169}170171return true;172}173174bool InitShadowWithReExec(bool init_origins) {175// Start with dry run: check layout is ok, but don't print warnings because176// warning messages will cause tests to fail (even if we successfully re-exec177// after the warning).178bool success = InitShadow(init_origins, true);179if (!success) {180# if SANITIZER_LINUX181// Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.182int old_personality = personality(0xffffffff);183bool aslr_on =184(old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);185186if (aslr_on) {187VReport(1,188"WARNING: MemorySanitizer: memory layout is incompatible, "189"possibly due to high-entropy ASLR.\n"190"Re-execing with fixed virtual address space.\n"191"N.B. reducing ASLR entropy is preferable.\n");192CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);193ReExec();194}195# endif196}197198// The earlier dry run didn't actually map or protect anything. Run again in199// non-dry run mode.200return success && InitShadow(init_origins, false);201}202203static void MsanAtExit(void) {204if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))205ReportStats();206if (msan_report_count > 0) {207ReportAtExitStatistics();208if (common_flags()->exitcode)209internal__exit(common_flags()->exitcode);210}211}212213void InstallAtExitHandler() {214atexit(MsanAtExit);215}216217// ---------------------- TSD ---------------- {{{1218219#if SANITIZER_NETBSD220// Thread Static Data cannot be used in early init on NetBSD.221// Reuse the MSan TSD API for compatibility with existing code222// with an alternative implementation.223224static void (*tsd_destructor)(void *tsd) = nullptr;225226struct tsd_key {227tsd_key() : key(nullptr) {}228~tsd_key() {229CHECK(tsd_destructor);230if (key)231(*tsd_destructor)(key);232}233MsanThread *key;234};235236static thread_local struct tsd_key key;237238void MsanTSDInit(void (*destructor)(void *tsd)) {239CHECK(!tsd_destructor);240tsd_destructor = destructor;241}242243MsanThread *GetCurrentThread() {244CHECK(tsd_destructor);245return key.key;246}247248void SetCurrentThread(MsanThread *tsd) {249CHECK(tsd_destructor);250CHECK(tsd);251CHECK(!key.key);252key.key = tsd;253}254255void MsanTSDDtor(void *tsd) {256CHECK(tsd_destructor);257CHECK_EQ(key.key, tsd);258key.key = nullptr;259// Make sure that signal handler can not see a stale current thread pointer.260atomic_signal_fence(memory_order_seq_cst);261MsanThread::TSDDtor(tsd);262}263#else264static pthread_key_t tsd_key;265static bool tsd_key_inited = false;266267void MsanTSDInit(void (*destructor)(void *tsd)) {268CHECK(!tsd_key_inited);269tsd_key_inited = true;270CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));271}272273static THREADLOCAL MsanThread* msan_current_thread;274275MsanThread *GetCurrentThread() {276return msan_current_thread;277}278279void SetCurrentThread(MsanThread *t) {280// Make sure we do not reset the current MsanThread.281CHECK_EQ(0, msan_current_thread);282msan_current_thread = t;283// Make sure that MsanTSDDtor gets called at the end.284CHECK(tsd_key_inited);285pthread_setspecific(tsd_key, (void *)t);286}287288void MsanTSDDtor(void *tsd) {289MsanThread *t = (MsanThread*)tsd;290if (t->destructor_iterations_ > 1) {291t->destructor_iterations_--;292CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));293return;294}295ScopedBlockSignals block(nullptr);296msan_current_thread = nullptr;297// Make sure that signal handler can not see a stale current thread pointer.298atomic_signal_fence(memory_order_seq_cst);299MsanThread::TSDDtor(tsd);300}301# endif302303static void BeforeFork() {304// Usually we lock ThreadRegistry, but msan does not have one.305LockAllocator();306StackDepotLockBeforeFork();307ChainedOriginDepotBeforeFork();308}309310static void AfterFork(bool fork_child) {311ChainedOriginDepotAfterFork(fork_child);312StackDepotUnlockAfterFork(fork_child);313UnlockAllocator();314// Usually we unlock ThreadRegistry, but msan does not have one.315}316317void InstallAtForkHandler() {318pthread_atfork(319&BeforeFork, []() { AfterFork(/* fork_child= */ false); },320[]() { AfterFork(/* fork_child= */ true); });321}322323} // namespace __msan324325#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD326327328