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