123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- //===-- msan_linux.cpp ----------------------------------------------------===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- // This file is a part of MemorySanitizer.
- //
- // Linux-, NetBSD- and FreeBSD-specific code.
- //===----------------------------------------------------------------------===//
- #include "sanitizer_common/sanitizer_platform.h"
- #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
- #include "msan.h"
- #include "msan_report.h"
- #include "msan_thread.h"
- #include <elf.h>
- #include <link.h>
- #include <pthread.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <unistd.h>
- #include <unwind.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include "sanitizer_common/sanitizer_common.h"
- #include "sanitizer_common/sanitizer_procmaps.h"
- namespace __msan {
- void ReportMapRange(const char *descr, uptr beg, uptr size) {
- if (size > 0) {
- uptr end = beg + size - 1;
- VPrintf(1, "%s : 0x%zx - 0x%zx\n", descr, beg, end);
- }
- }
- static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
- if (size > 0) {
- uptr end = beg + size - 1;
- if (!MemoryRangeIsAvailable(beg, end)) {
- Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end);
- return false;
- }
- }
- return true;
- }
- static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
- if (size > 0) {
- void *addr = MmapFixedNoAccess(beg, size, name);
- if (beg == 0 && addr) {
- // Depending on the kernel configuration, we may not be able to protect
- // the page at address zero.
- uptr gap = 16 * GetPageSizeCached();
- beg += gap;
- size -= gap;
- addr = MmapFixedNoAccess(beg, size, name);
- }
- if ((uptr)addr != beg) {
- uptr end = beg + size - 1;
- Printf("FATAL: Cannot protect memory range 0x%zx - 0x%zx (%s).\n", beg,
- end, name);
- return false;
- }
- }
- return true;
- }
- static void CheckMemoryLayoutSanity() {
- uptr prev_end = 0;
- for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
- uptr start = kMemoryLayout[i].start;
- uptr end = kMemoryLayout[i].end;
- MappingDesc::Type type = kMemoryLayout[i].type;
- CHECK_LT(start, end);
- CHECK_EQ(prev_end, start);
- CHECK(addr_is_type(start, type));
- CHECK(addr_is_type((start + end) / 2, type));
- CHECK(addr_is_type(end - 1, type));
- if (type == MappingDesc::APP) {
- uptr addr = start;
- CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
- CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
- CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
- addr = (start + end) / 2;
- CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
- CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
- CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
- addr = end - 1;
- CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
- CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
- CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
- }
- prev_end = end;
- }
- }
- bool InitShadow(bool init_origins) {
- // Let user know mapping parameters first.
- VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));
- for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
- VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
- kMemoryLayout[i].end - 1);
- CheckMemoryLayoutSanity();
- if (!MEM_IS_APP(&__msan_init)) {
- Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
- reinterpret_cast<void *>(&__msan_init));
- return false;
- }
- const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
- for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
- uptr start = kMemoryLayout[i].start;
- uptr end = kMemoryLayout[i].end;
- uptr size = end - start;
- MappingDesc::Type type = kMemoryLayout[i].type;
- // Check if the segment should be mapped based on platform constraints.
- if (start >= maxVirtualAddress)
- continue;
- bool map = type == MappingDesc::SHADOW ||
- (init_origins && type == MappingDesc::ORIGIN);
- bool protect = type == MappingDesc::INVALID ||
- (!init_origins && type == MappingDesc::ORIGIN);
- CHECK(!(map && protect));
- if (!map && !protect)
- CHECK(type == MappingDesc::APP);
- if (map) {
- if (!CheckMemoryRangeAvailability(start, size))
- return false;
- if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
- return false;
- if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(start, size);
- }
- if (protect) {
- if (!CheckMemoryRangeAvailability(start, size))
- return false;
- if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
- return false;
- }
- }
- return true;
- }
- static void MsanAtExit(void) {
- if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
- ReportStats();
- if (msan_report_count > 0) {
- ReportAtExitStatistics();
- if (common_flags()->exitcode)
- internal__exit(common_flags()->exitcode);
- }
- }
- void InstallAtExitHandler() {
- atexit(MsanAtExit);
- }
- // ---------------------- TSD ---------------- {{{1
- #if SANITIZER_NETBSD
- // Thread Static Data cannot be used in early init on NetBSD.
- // Reuse the MSan TSD API for compatibility with existing code
- // with an alternative implementation.
- static void (*tsd_destructor)(void *tsd) = nullptr;
- struct tsd_key {
- tsd_key() : key(nullptr) {}
- ~tsd_key() {
- CHECK(tsd_destructor);
- if (key)
- (*tsd_destructor)(key);
- }
- MsanThread *key;
- };
- static thread_local struct tsd_key key;
- void MsanTSDInit(void (*destructor)(void *tsd)) {
- CHECK(!tsd_destructor);
- tsd_destructor = destructor;
- }
- MsanThread *GetCurrentThread() {
- CHECK(tsd_destructor);
- return key.key;
- }
- void SetCurrentThread(MsanThread *tsd) {
- CHECK(tsd_destructor);
- CHECK(tsd);
- CHECK(!key.key);
- key.key = tsd;
- }
- void MsanTSDDtor(void *tsd) {
- CHECK(tsd_destructor);
- CHECK_EQ(key.key, tsd);
- key.key = nullptr;
- // Make sure that signal handler can not see a stale current thread pointer.
- atomic_signal_fence(memory_order_seq_cst);
- MsanThread::TSDDtor(tsd);
- }
- #else
- static pthread_key_t tsd_key;
- static bool tsd_key_inited = false;
- void MsanTSDInit(void (*destructor)(void *tsd)) {
- CHECK(!tsd_key_inited);
- tsd_key_inited = true;
- CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
- }
- static THREADLOCAL MsanThread* msan_current_thread;
- MsanThread *GetCurrentThread() {
- return msan_current_thread;
- }
- void SetCurrentThread(MsanThread *t) {
- // Make sure we do not reset the current MsanThread.
- CHECK_EQ(0, msan_current_thread);
- msan_current_thread = t;
- // Make sure that MsanTSDDtor gets called at the end.
- CHECK(tsd_key_inited);
- pthread_setspecific(tsd_key, (void *)t);
- }
- void MsanTSDDtor(void *tsd) {
- MsanThread *t = (MsanThread*)tsd;
- if (t->destructor_iterations_ > 1) {
- t->destructor_iterations_--;
- CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
- return;
- }
- msan_current_thread = nullptr;
- // Make sure that signal handler can not see a stale current thread pointer.
- atomic_signal_fence(memory_order_seq_cst);
- MsanThread::TSDDtor(tsd);
- }
- #endif
- } // namespace __msan
- #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
|