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