160c66db4SNico Weber //===-- msan_linux.cpp ----------------------------------------------------===// 260c66db4SNico Weber // 360c66db4SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 460c66db4SNico Weber // See https://llvm.org/LICENSE.txt for license information. 560c66db4SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 660c66db4SNico Weber // 760c66db4SNico Weber //===----------------------------------------------------------------------===// 860c66db4SNico Weber // 960c66db4SNico Weber // This file is a part of MemorySanitizer. 1060c66db4SNico Weber // 1160c66db4SNico Weber // Linux-, NetBSD- and FreeBSD-specific code. 1260c66db4SNico Weber //===----------------------------------------------------------------------===// 1360c66db4SNico Weber 1460c66db4SNico Weber #include "sanitizer_common/sanitizer_platform.h" 1560c66db4SNico Weber #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 1660c66db4SNico Weber 1760c66db4SNico Weber #include "msan.h" 1860c66db4SNico Weber #include "msan_report.h" 1960c66db4SNico Weber #include "msan_thread.h" 2060c66db4SNico Weber 2160c66db4SNico Weber #include <elf.h> 2260c66db4SNico Weber #include <link.h> 2360c66db4SNico Weber #include <pthread.h> 2460c66db4SNico Weber #include <stdio.h> 2560c66db4SNico Weber #include <stdlib.h> 2660c66db4SNico Weber #include <signal.h> 2760c66db4SNico Weber #include <unistd.h> 2860c66db4SNico Weber #include <unwind.h> 2960c66db4SNico Weber #include <sys/time.h> 3060c66db4SNico Weber #include <sys/resource.h> 3160c66db4SNico Weber 3260c66db4SNico Weber #include "sanitizer_common/sanitizer_common.h" 3360c66db4SNico Weber #include "sanitizer_common/sanitizer_procmaps.h" 3460c66db4SNico Weber 3560c66db4SNico Weber namespace __msan { 3660c66db4SNico Weber 3760c66db4SNico Weber void ReportMapRange(const char *descr, uptr beg, uptr size) { 3860c66db4SNico Weber if (size > 0) { 3960c66db4SNico Weber uptr end = beg + size - 1; 40*d26d5a0aSDmitry Vyukov VPrintf(1, "%s : 0x%zx - 0x%zx\n", descr, beg, end); 4160c66db4SNico Weber } 4260c66db4SNico Weber } 4360c66db4SNico Weber 4460c66db4SNico Weber static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { 4560c66db4SNico Weber if (size > 0) { 4660c66db4SNico Weber uptr end = beg + size - 1; 4760c66db4SNico Weber if (!MemoryRangeIsAvailable(beg, end)) { 48*d26d5a0aSDmitry Vyukov Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end); 4960c66db4SNico Weber return false; 5060c66db4SNico Weber } 5160c66db4SNico Weber } 5260c66db4SNico Weber return true; 5360c66db4SNico Weber } 5460c66db4SNico Weber 5560c66db4SNico Weber static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { 5660c66db4SNico Weber if (size > 0) { 5760c66db4SNico Weber void *addr = MmapFixedNoAccess(beg, size, name); 5860c66db4SNico Weber if (beg == 0 && addr) { 5960c66db4SNico Weber // Depending on the kernel configuration, we may not be able to protect 6060c66db4SNico Weber // the page at address zero. 6160c66db4SNico Weber uptr gap = 16 * GetPageSizeCached(); 6260c66db4SNico Weber beg += gap; 6360c66db4SNico Weber size -= gap; 6460c66db4SNico Weber addr = MmapFixedNoAccess(beg, size, name); 6560c66db4SNico Weber } 6660c66db4SNico Weber if ((uptr)addr != beg) { 6760c66db4SNico Weber uptr end = beg + size - 1; 68*d26d5a0aSDmitry Vyukov Printf("FATAL: Cannot protect memory range 0x%zx - 0x%zx (%s).\n", beg, 69*d26d5a0aSDmitry Vyukov end, name); 7060c66db4SNico Weber return false; 7160c66db4SNico Weber } 7260c66db4SNico Weber } 7360c66db4SNico Weber return true; 7460c66db4SNico Weber } 7560c66db4SNico Weber 7660c66db4SNico Weber static void CheckMemoryLayoutSanity() { 7760c66db4SNico Weber uptr prev_end = 0; 7860c66db4SNico Weber for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { 7960c66db4SNico Weber uptr start = kMemoryLayout[i].start; 8060c66db4SNico Weber uptr end = kMemoryLayout[i].end; 8160c66db4SNico Weber MappingDesc::Type type = kMemoryLayout[i].type; 8260c66db4SNico Weber CHECK_LT(start, end); 8360c66db4SNico Weber CHECK_EQ(prev_end, start); 8460c66db4SNico Weber CHECK(addr_is_type(start, type)); 8560c66db4SNico Weber CHECK(addr_is_type((start + end) / 2, type)); 8660c66db4SNico Weber CHECK(addr_is_type(end - 1, type)); 8760c66db4SNico Weber if (type == MappingDesc::APP) { 8860c66db4SNico Weber uptr addr = start; 8960c66db4SNico Weber CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 9060c66db4SNico Weber CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 9160c66db4SNico Weber CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 9260c66db4SNico Weber 9360c66db4SNico Weber addr = (start + end) / 2; 9460c66db4SNico Weber CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 9560c66db4SNico Weber CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 9660c66db4SNico Weber CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 9760c66db4SNico Weber 9860c66db4SNico Weber addr = end - 1; 9960c66db4SNico Weber CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 10060c66db4SNico Weber CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 10160c66db4SNico Weber CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 10260c66db4SNico Weber } 10360c66db4SNico Weber prev_end = end; 10460c66db4SNico Weber } 10560c66db4SNico Weber } 10660c66db4SNico Weber 10760c66db4SNico Weber bool InitShadow(bool init_origins) { 10860c66db4SNico Weber // Let user know mapping parameters first. 10960c66db4SNico Weber VPrintf(1, "__msan_init %p\n", &__msan_init); 11060c66db4SNico Weber for (unsigned i = 0; i < kMemoryLayoutSize; ++i) 11160c66db4SNico Weber VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, 11260c66db4SNico Weber kMemoryLayout[i].end - 1); 11360c66db4SNico Weber 11460c66db4SNico Weber CheckMemoryLayoutSanity(); 11560c66db4SNico Weber 11660c66db4SNico Weber if (!MEM_IS_APP(&__msan_init)) { 11760c66db4SNico Weber Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", 118*d26d5a0aSDmitry Vyukov &__msan_init); 11960c66db4SNico Weber return false; 12060c66db4SNico Weber } 12160c66db4SNico Weber 12260c66db4SNico Weber const uptr maxVirtualAddress = GetMaxUserVirtualAddress(); 12360c66db4SNico Weber 12460c66db4SNico Weber for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { 12560c66db4SNico Weber uptr start = kMemoryLayout[i].start; 12660c66db4SNico Weber uptr end = kMemoryLayout[i].end; 12760c66db4SNico Weber uptr size = end - start; 12860c66db4SNico Weber MappingDesc::Type type = kMemoryLayout[i].type; 12960c66db4SNico Weber 13060c66db4SNico Weber // Check if the segment should be mapped based on platform constraints. 13160c66db4SNico Weber if (start >= maxVirtualAddress) 13260c66db4SNico Weber continue; 13360c66db4SNico Weber 13460c66db4SNico Weber bool map = type == MappingDesc::SHADOW || 13560c66db4SNico Weber (init_origins && type == MappingDesc::ORIGIN); 13660c66db4SNico Weber bool protect = type == MappingDesc::INVALID || 13760c66db4SNico Weber (!init_origins && type == MappingDesc::ORIGIN); 13860c66db4SNico Weber CHECK(!(map && protect)); 13960c66db4SNico Weber if (!map && !protect) 14060c66db4SNico Weber CHECK(type == MappingDesc::APP); 14160c66db4SNico Weber if (map) { 14260c66db4SNico Weber if (!CheckMemoryRangeAvailability(start, size)) 14360c66db4SNico Weber return false; 144dc3388b0SEvgenii Stepanov if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) 14560c66db4SNico Weber return false; 14660c66db4SNico Weber if (common_flags()->use_madv_dontdump) 14760c66db4SNico Weber DontDumpShadowMemory(start, size); 14860c66db4SNico Weber } 14960c66db4SNico Weber if (protect) { 15060c66db4SNico Weber if (!CheckMemoryRangeAvailability(start, size)) 15160c66db4SNico Weber return false; 15260c66db4SNico Weber if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name)) 15360c66db4SNico Weber return false; 15460c66db4SNico Weber } 15560c66db4SNico Weber } 15660c66db4SNico Weber 15760c66db4SNico Weber return true; 15860c66db4SNico Weber } 15960c66db4SNico Weber 16060c66db4SNico Weber static void MsanAtExit(void) { 16160c66db4SNico Weber if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) 16260c66db4SNico Weber ReportStats(); 16360c66db4SNico Weber if (msan_report_count > 0) { 16460c66db4SNico Weber ReportAtExitStatistics(); 16560c66db4SNico Weber if (common_flags()->exitcode) 16660c66db4SNico Weber internal__exit(common_flags()->exitcode); 16760c66db4SNico Weber } 16860c66db4SNico Weber } 16960c66db4SNico Weber 17060c66db4SNico Weber void InstallAtExitHandler() { 17160c66db4SNico Weber atexit(MsanAtExit); 17260c66db4SNico Weber } 17360c66db4SNico Weber 17460c66db4SNico Weber // ---------------------- TSD ---------------- {{{1 17560c66db4SNico Weber 17660c66db4SNico Weber #if SANITIZER_NETBSD 17760c66db4SNico Weber // Thread Static Data cannot be used in early init on NetBSD. 17860c66db4SNico Weber // Reuse the MSan TSD API for compatibility with existing code 17960c66db4SNico Weber // with an alternative implementation. 18060c66db4SNico Weber 18160c66db4SNico Weber static void (*tsd_destructor)(void *tsd) = nullptr; 18260c66db4SNico Weber 18360c66db4SNico Weber struct tsd_key { 18460c66db4SNico Weber tsd_key() : key(nullptr) {} 18560c66db4SNico Weber ~tsd_key() { 18660c66db4SNico Weber CHECK(tsd_destructor); 18760c66db4SNico Weber if (key) 18860c66db4SNico Weber (*tsd_destructor)(key); 18960c66db4SNico Weber } 19060c66db4SNico Weber MsanThread *key; 19160c66db4SNico Weber }; 19260c66db4SNico Weber 19360c66db4SNico Weber static thread_local struct tsd_key key; 19460c66db4SNico Weber 19560c66db4SNico Weber void MsanTSDInit(void (*destructor)(void *tsd)) { 19660c66db4SNico Weber CHECK(!tsd_destructor); 19760c66db4SNico Weber tsd_destructor = destructor; 19860c66db4SNico Weber } 19960c66db4SNico Weber 20060c66db4SNico Weber MsanThread *GetCurrentThread() { 20160c66db4SNico Weber CHECK(tsd_destructor); 20260c66db4SNico Weber return key.key; 20360c66db4SNico Weber } 20460c66db4SNico Weber 20560c66db4SNico Weber void SetCurrentThread(MsanThread *tsd) { 20660c66db4SNico Weber CHECK(tsd_destructor); 20760c66db4SNico Weber CHECK(tsd); 20860c66db4SNico Weber CHECK(!key.key); 20960c66db4SNico Weber key.key = tsd; 21060c66db4SNico Weber } 21160c66db4SNico Weber 21260c66db4SNico Weber void MsanTSDDtor(void *tsd) { 21360c66db4SNico Weber CHECK(tsd_destructor); 21460c66db4SNico Weber CHECK_EQ(key.key, tsd); 21560c66db4SNico Weber key.key = nullptr; 21660c66db4SNico Weber // Make sure that signal handler can not see a stale current thread pointer. 21760c66db4SNico Weber atomic_signal_fence(memory_order_seq_cst); 21860c66db4SNico Weber MsanThread::TSDDtor(tsd); 21960c66db4SNico Weber } 22060c66db4SNico Weber #else 22160c66db4SNico Weber static pthread_key_t tsd_key; 22260c66db4SNico Weber static bool tsd_key_inited = false; 22360c66db4SNico Weber 22460c66db4SNico Weber void MsanTSDInit(void (*destructor)(void *tsd)) { 22560c66db4SNico Weber CHECK(!tsd_key_inited); 22660c66db4SNico Weber tsd_key_inited = true; 22760c66db4SNico Weber CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 22860c66db4SNico Weber } 22960c66db4SNico Weber 23060c66db4SNico Weber static THREADLOCAL MsanThread* msan_current_thread; 23160c66db4SNico Weber 23260c66db4SNico Weber MsanThread *GetCurrentThread() { 23360c66db4SNico Weber return msan_current_thread; 23460c66db4SNico Weber } 23560c66db4SNico Weber 23660c66db4SNico Weber void SetCurrentThread(MsanThread *t) { 23760c66db4SNico Weber // Make sure we do not reset the current MsanThread. 23860c66db4SNico Weber CHECK_EQ(0, msan_current_thread); 23960c66db4SNico Weber msan_current_thread = t; 24060c66db4SNico Weber // Make sure that MsanTSDDtor gets called at the end. 24160c66db4SNico Weber CHECK(tsd_key_inited); 24260c66db4SNico Weber pthread_setspecific(tsd_key, (void *)t); 24360c66db4SNico Weber } 24460c66db4SNico Weber 24560c66db4SNico Weber void MsanTSDDtor(void *tsd) { 24660c66db4SNico Weber MsanThread *t = (MsanThread*)tsd; 24760c66db4SNico Weber if (t->destructor_iterations_ > 1) { 24860c66db4SNico Weber t->destructor_iterations_--; 24960c66db4SNico Weber CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 25060c66db4SNico Weber return; 25160c66db4SNico Weber } 25260c66db4SNico Weber msan_current_thread = nullptr; 25360c66db4SNico Weber // Make sure that signal handler can not see a stale current thread pointer. 25460c66db4SNico Weber atomic_signal_fence(memory_order_seq_cst); 25560c66db4SNico Weber MsanThread::TSDDtor(tsd); 25660c66db4SNico Weber } 25760c66db4SNico Weber #endif 25860c66db4SNico Weber 25960c66db4SNico Weber } // namespace __msan 26060c66db4SNico Weber 26160c66db4SNico Weber #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 262