1*68d75effSDimitry Andric //===-- msan_linux.cpp ----------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of MemorySanitizer. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // Linux-, NetBSD- and FreeBSD-specific code. 12*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 13*68d75effSDimitry Andric 14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 15*68d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 16*68d75effSDimitry Andric 17*68d75effSDimitry Andric #include "msan.h" 18*68d75effSDimitry Andric #include "msan_report.h" 19*68d75effSDimitry Andric #include "msan_thread.h" 20*68d75effSDimitry Andric 21*68d75effSDimitry Andric #include <elf.h> 22*68d75effSDimitry Andric #include <link.h> 23*68d75effSDimitry Andric #include <pthread.h> 24*68d75effSDimitry Andric #include <stdio.h> 25*68d75effSDimitry Andric #include <stdlib.h> 26*68d75effSDimitry Andric #include <signal.h> 27*68d75effSDimitry Andric #include <unistd.h> 28*68d75effSDimitry Andric #include <unwind.h> 29*68d75effSDimitry Andric #include <execinfo.h> 30*68d75effSDimitry Andric #include <sys/time.h> 31*68d75effSDimitry Andric #include <sys/resource.h> 32*68d75effSDimitry Andric 33*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 34*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_procmaps.h" 35*68d75effSDimitry Andric 36*68d75effSDimitry Andric namespace __msan { 37*68d75effSDimitry Andric 38*68d75effSDimitry Andric void ReportMapRange(const char *descr, uptr beg, uptr size) { 39*68d75effSDimitry Andric if (size > 0) { 40*68d75effSDimitry Andric uptr end = beg + size - 1; 41*68d75effSDimitry Andric VPrintf(1, "%s : %p - %p\n", descr, beg, end); 42*68d75effSDimitry Andric } 43*68d75effSDimitry Andric } 44*68d75effSDimitry Andric 45*68d75effSDimitry Andric static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { 46*68d75effSDimitry Andric if (size > 0) { 47*68d75effSDimitry Andric uptr end = beg + size - 1; 48*68d75effSDimitry Andric if (!MemoryRangeIsAvailable(beg, end)) { 49*68d75effSDimitry Andric Printf("FATAL: Memory range %p - %p is not available.\n", beg, end); 50*68d75effSDimitry Andric return false; 51*68d75effSDimitry Andric } 52*68d75effSDimitry Andric } 53*68d75effSDimitry Andric return true; 54*68d75effSDimitry Andric } 55*68d75effSDimitry Andric 56*68d75effSDimitry Andric static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { 57*68d75effSDimitry Andric if (size > 0) { 58*68d75effSDimitry Andric void *addr = MmapFixedNoAccess(beg, size, name); 59*68d75effSDimitry Andric if (beg == 0 && addr) { 60*68d75effSDimitry Andric // Depending on the kernel configuration, we may not be able to protect 61*68d75effSDimitry Andric // the page at address zero. 62*68d75effSDimitry Andric uptr gap = 16 * GetPageSizeCached(); 63*68d75effSDimitry Andric beg += gap; 64*68d75effSDimitry Andric size -= gap; 65*68d75effSDimitry Andric addr = MmapFixedNoAccess(beg, size, name); 66*68d75effSDimitry Andric } 67*68d75effSDimitry Andric if ((uptr)addr != beg) { 68*68d75effSDimitry Andric uptr end = beg + size - 1; 69*68d75effSDimitry Andric Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end, 70*68d75effSDimitry Andric name); 71*68d75effSDimitry Andric return false; 72*68d75effSDimitry Andric } 73*68d75effSDimitry Andric } 74*68d75effSDimitry Andric return true; 75*68d75effSDimitry Andric } 76*68d75effSDimitry Andric 77*68d75effSDimitry Andric static void CheckMemoryLayoutSanity() { 78*68d75effSDimitry Andric uptr prev_end = 0; 79*68d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { 80*68d75effSDimitry Andric uptr start = kMemoryLayout[i].start; 81*68d75effSDimitry Andric uptr end = kMemoryLayout[i].end; 82*68d75effSDimitry Andric MappingDesc::Type type = kMemoryLayout[i].type; 83*68d75effSDimitry Andric CHECK_LT(start, end); 84*68d75effSDimitry Andric CHECK_EQ(prev_end, start); 85*68d75effSDimitry Andric CHECK(addr_is_type(start, type)); 86*68d75effSDimitry Andric CHECK(addr_is_type((start + end) / 2, type)); 87*68d75effSDimitry Andric CHECK(addr_is_type(end - 1, type)); 88*68d75effSDimitry Andric if (type == MappingDesc::APP) { 89*68d75effSDimitry Andric uptr addr = start; 90*68d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 91*68d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 92*68d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 93*68d75effSDimitry Andric 94*68d75effSDimitry Andric addr = (start + end) / 2; 95*68d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 96*68d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 97*68d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 98*68d75effSDimitry Andric 99*68d75effSDimitry Andric addr = end - 1; 100*68d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr))); 101*68d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr))); 102*68d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr))); 103*68d75effSDimitry Andric } 104*68d75effSDimitry Andric prev_end = end; 105*68d75effSDimitry Andric } 106*68d75effSDimitry Andric } 107*68d75effSDimitry Andric 108*68d75effSDimitry Andric bool InitShadow(bool init_origins) { 109*68d75effSDimitry Andric // Let user know mapping parameters first. 110*68d75effSDimitry Andric VPrintf(1, "__msan_init %p\n", &__msan_init); 111*68d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) 112*68d75effSDimitry Andric VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, 113*68d75effSDimitry Andric kMemoryLayout[i].end - 1); 114*68d75effSDimitry Andric 115*68d75effSDimitry Andric CheckMemoryLayoutSanity(); 116*68d75effSDimitry Andric 117*68d75effSDimitry Andric if (!MEM_IS_APP(&__msan_init)) { 118*68d75effSDimitry Andric Printf("FATAL: Code %p is out of application range. Non-PIE build?\n", 119*68d75effSDimitry Andric (uptr)&__msan_init); 120*68d75effSDimitry Andric return false; 121*68d75effSDimitry Andric } 122*68d75effSDimitry Andric 123*68d75effSDimitry Andric const uptr maxVirtualAddress = GetMaxUserVirtualAddress(); 124*68d75effSDimitry Andric 125*68d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { 126*68d75effSDimitry Andric uptr start = kMemoryLayout[i].start; 127*68d75effSDimitry Andric uptr end = kMemoryLayout[i].end; 128*68d75effSDimitry Andric uptr size = end - start; 129*68d75effSDimitry Andric MappingDesc::Type type = kMemoryLayout[i].type; 130*68d75effSDimitry Andric 131*68d75effSDimitry Andric // Check if the segment should be mapped based on platform constraints. 132*68d75effSDimitry Andric if (start >= maxVirtualAddress) 133*68d75effSDimitry Andric continue; 134*68d75effSDimitry Andric 135*68d75effSDimitry Andric bool map = type == MappingDesc::SHADOW || 136*68d75effSDimitry Andric (init_origins && type == MappingDesc::ORIGIN); 137*68d75effSDimitry Andric bool protect = type == MappingDesc::INVALID || 138*68d75effSDimitry Andric (!init_origins && type == MappingDesc::ORIGIN); 139*68d75effSDimitry Andric CHECK(!(map && protect)); 140*68d75effSDimitry Andric if (!map && !protect) 141*68d75effSDimitry Andric CHECK(type == MappingDesc::APP); 142*68d75effSDimitry Andric if (map) { 143*68d75effSDimitry Andric if (!CheckMemoryRangeAvailability(start, size)) 144*68d75effSDimitry Andric return false; 145*68d75effSDimitry Andric if (!MmapFixedNoReserve(start, size, kMemoryLayout[i].name)) 146*68d75effSDimitry Andric return false; 147*68d75effSDimitry Andric if (common_flags()->use_madv_dontdump) 148*68d75effSDimitry Andric DontDumpShadowMemory(start, size); 149*68d75effSDimitry Andric } 150*68d75effSDimitry Andric if (protect) { 151*68d75effSDimitry Andric if (!CheckMemoryRangeAvailability(start, size)) 152*68d75effSDimitry Andric return false; 153*68d75effSDimitry Andric if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name)) 154*68d75effSDimitry Andric return false; 155*68d75effSDimitry Andric } 156*68d75effSDimitry Andric } 157*68d75effSDimitry Andric 158*68d75effSDimitry Andric return true; 159*68d75effSDimitry Andric } 160*68d75effSDimitry Andric 161*68d75effSDimitry Andric static void MsanAtExit(void) { 162*68d75effSDimitry Andric if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) 163*68d75effSDimitry Andric ReportStats(); 164*68d75effSDimitry Andric if (msan_report_count > 0) { 165*68d75effSDimitry Andric ReportAtExitStatistics(); 166*68d75effSDimitry Andric if (common_flags()->exitcode) 167*68d75effSDimitry Andric internal__exit(common_flags()->exitcode); 168*68d75effSDimitry Andric } 169*68d75effSDimitry Andric } 170*68d75effSDimitry Andric 171*68d75effSDimitry Andric void InstallAtExitHandler() { 172*68d75effSDimitry Andric atexit(MsanAtExit); 173*68d75effSDimitry Andric } 174*68d75effSDimitry Andric 175*68d75effSDimitry Andric // ---------------------- TSD ---------------- {{{1 176*68d75effSDimitry Andric 177*68d75effSDimitry Andric #if SANITIZER_NETBSD 178*68d75effSDimitry Andric // Thread Static Data cannot be used in early init on NetBSD. 179*68d75effSDimitry Andric // Reuse the MSan TSD API for compatibility with existing code 180*68d75effSDimitry Andric // with an alternative implementation. 181*68d75effSDimitry Andric 182*68d75effSDimitry Andric static void (*tsd_destructor)(void *tsd) = nullptr; 183*68d75effSDimitry Andric 184*68d75effSDimitry Andric struct tsd_key { 185*68d75effSDimitry Andric tsd_key() : key(nullptr) {} 186*68d75effSDimitry Andric ~tsd_key() { 187*68d75effSDimitry Andric CHECK(tsd_destructor); 188*68d75effSDimitry Andric if (key) 189*68d75effSDimitry Andric (*tsd_destructor)(key); 190*68d75effSDimitry Andric } 191*68d75effSDimitry Andric MsanThread *key; 192*68d75effSDimitry Andric }; 193*68d75effSDimitry Andric 194*68d75effSDimitry Andric static thread_local struct tsd_key key; 195*68d75effSDimitry Andric 196*68d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) { 197*68d75effSDimitry Andric CHECK(!tsd_destructor); 198*68d75effSDimitry Andric tsd_destructor = destructor; 199*68d75effSDimitry Andric } 200*68d75effSDimitry Andric 201*68d75effSDimitry Andric MsanThread *GetCurrentThread() { 202*68d75effSDimitry Andric CHECK(tsd_destructor); 203*68d75effSDimitry Andric return key.key; 204*68d75effSDimitry Andric } 205*68d75effSDimitry Andric 206*68d75effSDimitry Andric void SetCurrentThread(MsanThread *tsd) { 207*68d75effSDimitry Andric CHECK(tsd_destructor); 208*68d75effSDimitry Andric CHECK(tsd); 209*68d75effSDimitry Andric CHECK(!key.key); 210*68d75effSDimitry Andric key.key = tsd; 211*68d75effSDimitry Andric } 212*68d75effSDimitry Andric 213*68d75effSDimitry Andric void MsanTSDDtor(void *tsd) { 214*68d75effSDimitry Andric CHECK(tsd_destructor); 215*68d75effSDimitry Andric CHECK_EQ(key.key, tsd); 216*68d75effSDimitry Andric key.key = nullptr; 217*68d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer. 218*68d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst); 219*68d75effSDimitry Andric MsanThread::TSDDtor(tsd); 220*68d75effSDimitry Andric } 221*68d75effSDimitry Andric #else 222*68d75effSDimitry Andric static pthread_key_t tsd_key; 223*68d75effSDimitry Andric static bool tsd_key_inited = false; 224*68d75effSDimitry Andric 225*68d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) { 226*68d75effSDimitry Andric CHECK(!tsd_key_inited); 227*68d75effSDimitry Andric tsd_key_inited = true; 228*68d75effSDimitry Andric CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 229*68d75effSDimitry Andric } 230*68d75effSDimitry Andric 231*68d75effSDimitry Andric static THREADLOCAL MsanThread* msan_current_thread; 232*68d75effSDimitry Andric 233*68d75effSDimitry Andric MsanThread *GetCurrentThread() { 234*68d75effSDimitry Andric return msan_current_thread; 235*68d75effSDimitry Andric } 236*68d75effSDimitry Andric 237*68d75effSDimitry Andric void SetCurrentThread(MsanThread *t) { 238*68d75effSDimitry Andric // Make sure we do not reset the current MsanThread. 239*68d75effSDimitry Andric CHECK_EQ(0, msan_current_thread); 240*68d75effSDimitry Andric msan_current_thread = t; 241*68d75effSDimitry Andric // Make sure that MsanTSDDtor gets called at the end. 242*68d75effSDimitry Andric CHECK(tsd_key_inited); 243*68d75effSDimitry Andric pthread_setspecific(tsd_key, (void *)t); 244*68d75effSDimitry Andric } 245*68d75effSDimitry Andric 246*68d75effSDimitry Andric void MsanTSDDtor(void *tsd) { 247*68d75effSDimitry Andric MsanThread *t = (MsanThread*)tsd; 248*68d75effSDimitry Andric if (t->destructor_iterations_ > 1) { 249*68d75effSDimitry Andric t->destructor_iterations_--; 250*68d75effSDimitry Andric CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 251*68d75effSDimitry Andric return; 252*68d75effSDimitry Andric } 253*68d75effSDimitry Andric msan_current_thread = nullptr; 254*68d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer. 255*68d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst); 256*68d75effSDimitry Andric MsanThread::TSDDtor(tsd); 257*68d75effSDimitry Andric } 258*68d75effSDimitry Andric #endif 259*68d75effSDimitry Andric 260*68d75effSDimitry Andric } // namespace __msan 261*68d75effSDimitry Andric 262*68d75effSDimitry Andric #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 263