168d75effSDimitry Andric //===-- msan_linux.cpp ----------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of MemorySanitizer. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Linux-, NetBSD- and FreeBSD-specific code. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 1568d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 1668d75effSDimitry Andric 1768d75effSDimitry Andric # include <elf.h> 1868d75effSDimitry Andric # include <link.h> 1968d75effSDimitry Andric # include <pthread.h> 205f757f3fSDimitry Andric # include <signal.h> 2168d75effSDimitry Andric # include <stdio.h> 2268d75effSDimitry Andric # include <stdlib.h> 23439352acSDimitry Andric # if SANITIZER_LINUX 24439352acSDimitry Andric # include <sys/personality.h> 25439352acSDimitry Andric # endif 265f757f3fSDimitry Andric # include <sys/resource.h> 275f757f3fSDimitry Andric # include <sys/time.h> 2868d75effSDimitry Andric # include <unistd.h> 2968d75effSDimitry Andric # include <unwind.h> 3068d75effSDimitry Andric 315f757f3fSDimitry Andric # include "msan.h" 325f757f3fSDimitry Andric # include "msan_allocator.h" 335f757f3fSDimitry Andric # include "msan_chained_origin_depot.h" 345f757f3fSDimitry Andric # include "msan_report.h" 355f757f3fSDimitry Andric # include "msan_thread.h" 3668d75effSDimitry Andric # include "sanitizer_common/sanitizer_common.h" 3768d75effSDimitry Andric # include "sanitizer_common/sanitizer_procmaps.h" 385f757f3fSDimitry Andric # include "sanitizer_common/sanitizer_stackdepot.h" 3968d75effSDimitry Andric 4068d75effSDimitry Andric namespace __msan { 4168d75effSDimitry Andric 4268d75effSDimitry Andric void ReportMapRange(const char *descr, uptr beg, uptr size) { 4368d75effSDimitry Andric if (size > 0) { 4468d75effSDimitry Andric uptr end = beg + size - 1; 45*0fca6ea1SDimitry Andric VPrintf(1, "%s : %p-%p\n", descr, (void *)beg, (void *)end); 4668d75effSDimitry Andric } 4768d75effSDimitry Andric } 4868d75effSDimitry Andric 49439352acSDimitry Andric static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) { 5068d75effSDimitry Andric if (size > 0) { 5168d75effSDimitry Andric uptr end = beg + size - 1; 5268d75effSDimitry Andric if (!MemoryRangeIsAvailable(beg, end)) { 53439352acSDimitry Andric if (verbose) 54*0fca6ea1SDimitry Andric Printf("FATAL: MemorySanitizer: Shadow range %p-%p is not available.\n", 55*0fca6ea1SDimitry Andric (void *)beg, (void *)end); 5668d75effSDimitry Andric return false; 5768d75effSDimitry Andric } 5868d75effSDimitry Andric } 5968d75effSDimitry Andric return true; 6068d75effSDimitry Andric } 6168d75effSDimitry Andric 6268d75effSDimitry Andric static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { 6368d75effSDimitry Andric if (size > 0) { 6468d75effSDimitry Andric void *addr = MmapFixedNoAccess(beg, size, name); 6568d75effSDimitry Andric if (beg == 0 && addr) { 6668d75effSDimitry Andric // Depending on the kernel configuration, we may not be able to protect 6768d75effSDimitry Andric // the page at address zero. 6868d75effSDimitry Andric uptr gap = 16 * GetPageSizeCached(); 6968d75effSDimitry Andric beg += gap; 7068d75effSDimitry Andric size -= gap; 7168d75effSDimitry Andric addr = MmapFixedNoAccess(beg, size, name); 7268d75effSDimitry Andric } 7368d75effSDimitry Andric if ((uptr)addr != beg) { 7468d75effSDimitry Andric uptr end = beg + size - 1; 75*0fca6ea1SDimitry Andric Printf( 76*0fca6ea1SDimitry Andric "FATAL: MemorySanitizer: Cannot protect memory range %p-%p (%s).\n", 77*0fca6ea1SDimitry Andric (void *)beg, (void *)end, name); 7868d75effSDimitry Andric return false; 7968d75effSDimitry Andric } 8068d75effSDimitry Andric } 8168d75effSDimitry Andric return true; 8268d75effSDimitry Andric } 8368d75effSDimitry Andric 8468d75effSDimitry Andric static void CheckMemoryLayoutSanity() { 8568d75effSDimitry Andric uptr prev_end = 0; 8668d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { 8768d75effSDimitry Andric uptr start = kMemoryLayout[i].start; 8868d75effSDimitry Andric uptr end = kMemoryLayout[i].end; 8968d75effSDimitry Andric MappingDesc::Type type = kMemoryLayout[i].type; 9068d75effSDimitry Andric CHECK_LT(start, end); 9168d75effSDimitry Andric CHECK_EQ(prev_end, start); 9268d75effSDimitry Andric CHECK(addr_is_type(start, type)); 9368d75effSDimitry Andric CHECK(addr_is_type((start + end) / 2, type)); 9468d75effSDimitry Andric CHECK(addr_is_type(end - 1, type)); 95439352acSDimitry Andric if (type == MappingDesc::APP || type == MappingDesc::ALLOCATOR) { 9668d75effSDimitry Andric uptr addr = start; 9768d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 9868d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 9968d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 10068d75effSDimitry Andric 10168d75effSDimitry Andric addr = (start + end) / 2; 10268d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 10368d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 10468d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 10568d75effSDimitry Andric 10668d75effSDimitry Andric addr = end - 1; 10768d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 10868d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 10968d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 11068d75effSDimitry Andric } 11168d75effSDimitry Andric prev_end = end; 11268d75effSDimitry Andric } 11368d75effSDimitry Andric } 11468d75effSDimitry Andric 115439352acSDimitry Andric static bool InitShadow(bool init_origins, bool dry_run) { 11668d75effSDimitry Andric // Let user know mapping parameters first. 117349cc55cSDimitry Andric VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init)); 11868d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) 11968d75effSDimitry Andric VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, 12068d75effSDimitry Andric kMemoryLayout[i].end - 1); 12168d75effSDimitry Andric 12268d75effSDimitry Andric CheckMemoryLayoutSanity(); 12368d75effSDimitry Andric 12468d75effSDimitry Andric if (!MEM_IS_APP(&__msan_init)) { 125439352acSDimitry Andric if (!dry_run) 12668d75effSDimitry Andric Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", 127349cc55cSDimitry Andric reinterpret_cast<void *>(&__msan_init)); 12868d75effSDimitry Andric return false; 12968d75effSDimitry Andric } 13068d75effSDimitry Andric 13168d75effSDimitry Andric const uptr maxVirtualAddress = GetMaxUserVirtualAddress(); 13268d75effSDimitry Andric 13368d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { 13468d75effSDimitry Andric uptr start = kMemoryLayout[i].start; 13568d75effSDimitry Andric uptr end = kMemoryLayout[i].end; 13668d75effSDimitry Andric uptr size = end - start; 13768d75effSDimitry Andric MappingDesc::Type type = kMemoryLayout[i].type; 13868d75effSDimitry Andric 13968d75effSDimitry Andric // Check if the segment should be mapped based on platform constraints. 14068d75effSDimitry Andric if (start >= maxVirtualAddress) 14168d75effSDimitry Andric continue; 14268d75effSDimitry Andric 14368d75effSDimitry Andric bool map = type == MappingDesc::SHADOW || 14468d75effSDimitry Andric (init_origins && type == MappingDesc::ORIGIN); 14568d75effSDimitry Andric bool protect = type == MappingDesc::INVALID || 14668d75effSDimitry Andric (!init_origins && type == MappingDesc::ORIGIN); 14768d75effSDimitry Andric CHECK(!(map && protect)); 148439352acSDimitry Andric if (!map && !protect) { 149439352acSDimitry Andric CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR); 150439352acSDimitry Andric 151439352acSDimitry Andric if (dry_run && type == MappingDesc::ALLOCATOR && 152439352acSDimitry Andric !CheckMemoryRangeAvailability(start, size, !dry_run)) 153439352acSDimitry Andric return false; 154439352acSDimitry Andric } 15568d75effSDimitry Andric if (map) { 156439352acSDimitry Andric if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run)) 15768d75effSDimitry Andric return false; 158439352acSDimitry Andric if (!dry_run && 159439352acSDimitry Andric !MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) 16068d75effSDimitry Andric return false; 161439352acSDimitry Andric if (!dry_run && common_flags()->use_madv_dontdump) 16268d75effSDimitry Andric DontDumpShadowMemory(start, size); 16368d75effSDimitry Andric } 16468d75effSDimitry Andric if (protect) { 165439352acSDimitry Andric if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run)) 16668d75effSDimitry Andric return false; 167439352acSDimitry Andric if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name)) 16868d75effSDimitry Andric return false; 16968d75effSDimitry Andric } 17068d75effSDimitry Andric } 17168d75effSDimitry Andric 17268d75effSDimitry Andric return true; 17368d75effSDimitry Andric } 17468d75effSDimitry Andric 175439352acSDimitry Andric bool InitShadowWithReExec(bool init_origins) { 176439352acSDimitry Andric // Start with dry run: check layout is ok, but don't print warnings because 177439352acSDimitry Andric // warning messages will cause tests to fail (even if we successfully re-exec 178439352acSDimitry Andric // after the warning). 179*0fca6ea1SDimitry Andric bool success = InitShadow(init_origins, true); 180439352acSDimitry Andric if (!success) { 181439352acSDimitry Andric # if SANITIZER_LINUX 182439352acSDimitry Andric // Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it. 183439352acSDimitry Andric int old_personality = personality(0xffffffff); 184439352acSDimitry Andric bool aslr_on = 185439352acSDimitry Andric (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0); 186439352acSDimitry Andric 187439352acSDimitry Andric if (aslr_on) { 188439352acSDimitry Andric VReport(1, 189439352acSDimitry Andric "WARNING: MemorySanitizer: memory layout is incompatible, " 190439352acSDimitry Andric "possibly due to high-entropy ASLR.\n" 191439352acSDimitry Andric "Re-execing with fixed virtual address space.\n" 192439352acSDimitry Andric "N.B. reducing ASLR entropy is preferable.\n"); 193439352acSDimitry Andric CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); 194439352acSDimitry Andric ReExec(); 195439352acSDimitry Andric } 196439352acSDimitry Andric # endif 197439352acSDimitry Andric } 198439352acSDimitry Andric 199439352acSDimitry Andric // The earlier dry run didn't actually map or protect anything. Run again in 200439352acSDimitry Andric // non-dry run mode. 201*0fca6ea1SDimitry Andric return success && InitShadow(init_origins, false); 202439352acSDimitry Andric } 203439352acSDimitry Andric 20468d75effSDimitry Andric static void MsanAtExit(void) { 20568d75effSDimitry Andric if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) 20668d75effSDimitry Andric ReportStats(); 20768d75effSDimitry Andric if (msan_report_count > 0) { 20868d75effSDimitry Andric ReportAtExitStatistics(); 20968d75effSDimitry Andric if (common_flags()->exitcode) 21068d75effSDimitry Andric internal__exit(common_flags()->exitcode); 21168d75effSDimitry Andric } 21268d75effSDimitry Andric } 21368d75effSDimitry Andric 21468d75effSDimitry Andric void InstallAtExitHandler() { 21568d75effSDimitry Andric atexit(MsanAtExit); 21668d75effSDimitry Andric } 21768d75effSDimitry Andric 21868d75effSDimitry Andric // ---------------------- TSD ---------------- {{{1 21968d75effSDimitry Andric 22068d75effSDimitry Andric #if SANITIZER_NETBSD 22168d75effSDimitry Andric // Thread Static Data cannot be used in early init on NetBSD. 22268d75effSDimitry Andric // Reuse the MSan TSD API for compatibility with existing code 22368d75effSDimitry Andric // with an alternative implementation. 22468d75effSDimitry Andric 22568d75effSDimitry Andric static void (*tsd_destructor)(void *tsd) = nullptr; 22668d75effSDimitry Andric 22768d75effSDimitry Andric struct tsd_key { 22868d75effSDimitry Andric tsd_key() : key(nullptr) {} 22968d75effSDimitry Andric ~tsd_key() { 23068d75effSDimitry Andric CHECK(tsd_destructor); 23168d75effSDimitry Andric if (key) 23268d75effSDimitry Andric (*tsd_destructor)(key); 23368d75effSDimitry Andric } 23468d75effSDimitry Andric MsanThread *key; 23568d75effSDimitry Andric }; 23668d75effSDimitry Andric 23768d75effSDimitry Andric static thread_local struct tsd_key key; 23868d75effSDimitry Andric 23968d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) { 24068d75effSDimitry Andric CHECK(!tsd_destructor); 24168d75effSDimitry Andric tsd_destructor = destructor; 24268d75effSDimitry Andric } 24368d75effSDimitry Andric 24468d75effSDimitry Andric MsanThread *GetCurrentThread() { 24568d75effSDimitry Andric CHECK(tsd_destructor); 24668d75effSDimitry Andric return key.key; 24768d75effSDimitry Andric } 24868d75effSDimitry Andric 24968d75effSDimitry Andric void SetCurrentThread(MsanThread *tsd) { 25068d75effSDimitry Andric CHECK(tsd_destructor); 25168d75effSDimitry Andric CHECK(tsd); 25268d75effSDimitry Andric CHECK(!key.key); 25368d75effSDimitry Andric key.key = tsd; 25468d75effSDimitry Andric } 25568d75effSDimitry Andric 25668d75effSDimitry Andric void MsanTSDDtor(void *tsd) { 25768d75effSDimitry Andric CHECK(tsd_destructor); 25868d75effSDimitry Andric CHECK_EQ(key.key, tsd); 25968d75effSDimitry Andric key.key = nullptr; 26068d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer. 26168d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst); 26268d75effSDimitry Andric MsanThread::TSDDtor(tsd); 26368d75effSDimitry Andric } 26468d75effSDimitry Andric #else 26568d75effSDimitry Andric static pthread_key_t tsd_key; 26668d75effSDimitry Andric static bool tsd_key_inited = false; 26768d75effSDimitry Andric 26868d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) { 26968d75effSDimitry Andric CHECK(!tsd_key_inited); 27068d75effSDimitry Andric tsd_key_inited = true; 27168d75effSDimitry Andric CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 27268d75effSDimitry Andric } 27368d75effSDimitry Andric 27468d75effSDimitry Andric static THREADLOCAL MsanThread* msan_current_thread; 27568d75effSDimitry Andric 27668d75effSDimitry Andric MsanThread *GetCurrentThread() { 27768d75effSDimitry Andric return msan_current_thread; 27868d75effSDimitry Andric } 27968d75effSDimitry Andric 28068d75effSDimitry Andric void SetCurrentThread(MsanThread *t) { 28168d75effSDimitry Andric // Make sure we do not reset the current MsanThread. 28268d75effSDimitry Andric CHECK_EQ(0, msan_current_thread); 28368d75effSDimitry Andric msan_current_thread = t; 28468d75effSDimitry Andric // Make sure that MsanTSDDtor gets called at the end. 28568d75effSDimitry Andric CHECK(tsd_key_inited); 28668d75effSDimitry Andric pthread_setspecific(tsd_key, (void *)t); 28768d75effSDimitry Andric } 28868d75effSDimitry Andric 28968d75effSDimitry Andric void MsanTSDDtor(void *tsd) { 29068d75effSDimitry Andric MsanThread *t = (MsanThread*)tsd; 29168d75effSDimitry Andric if (t->destructor_iterations_ > 1) { 29268d75effSDimitry Andric t->destructor_iterations_--; 29368d75effSDimitry Andric CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 29468d75effSDimitry Andric return; 29568d75effSDimitry Andric } 296*0fca6ea1SDimitry Andric ScopedBlockSignals block(nullptr); 29768d75effSDimitry Andric msan_current_thread = nullptr; 29868d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer. 29968d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst); 30068d75effSDimitry Andric MsanThread::TSDDtor(tsd); 30168d75effSDimitry Andric } 30268d75effSDimitry Andric # endif 30368d75effSDimitry Andric 304cb14a3feSDimitry Andric static void BeforeFork() { 3055f757f3fSDimitry Andric // Usually we lock ThreadRegistry, but msan does not have one. 3065f757f3fSDimitry Andric LockAllocator(); 307cb14a3feSDimitry Andric StackDepotLockBeforeFork(); 308cb14a3feSDimitry Andric ChainedOriginDepotBeforeFork(); 309cb14a3feSDimitry Andric } 310cb14a3feSDimitry Andric 311cb14a3feSDimitry Andric static void AfterFork(bool fork_child) { 312cb14a3feSDimitry Andric ChainedOriginDepotAfterFork(fork_child); 313cb14a3feSDimitry Andric StackDepotUnlockAfterFork(fork_child); 3145f757f3fSDimitry Andric UnlockAllocator(); 3155f757f3fSDimitry Andric // Usually we unlock ThreadRegistry, but msan does not have one. 316cb14a3feSDimitry Andric } 317cb14a3feSDimitry Andric 318cb14a3feSDimitry Andric void InstallAtForkHandler() { 319cb14a3feSDimitry Andric pthread_atfork( 320cb14a3feSDimitry Andric &BeforeFork, []() { AfterFork(/* fork_child= */ false); }, 321cb14a3feSDimitry Andric []() { AfterFork(/* fork_child= */ true); }); 3225f757f3fSDimitry Andric } 3235f757f3fSDimitry Andric 32468d75effSDimitry Andric } // namespace __msan 32568d75effSDimitry Andric 32668d75effSDimitry Andric #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 327