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