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