160c66db4SNico Weber //===-- msan_linux.cpp ----------------------------------------------------===//
260c66db4SNico Weber //
360c66db4SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
460c66db4SNico Weber // See https://llvm.org/LICENSE.txt for license information.
560c66db4SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
660c66db4SNico Weber //
760c66db4SNico Weber //===----------------------------------------------------------------------===//
860c66db4SNico Weber //
960c66db4SNico Weber // This file is a part of MemorySanitizer.
1060c66db4SNico Weber //
1160c66db4SNico Weber // Linux-, NetBSD- and FreeBSD-specific code.
1260c66db4SNico Weber //===----------------------------------------------------------------------===//
1360c66db4SNico Weber 
1460c66db4SNico Weber #include "sanitizer_common/sanitizer_platform.h"
1560c66db4SNico Weber #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
1660c66db4SNico Weber 
1760c66db4SNico Weber #include "msan.h"
1860c66db4SNico Weber #include "msan_report.h"
1960c66db4SNico Weber #include "msan_thread.h"
2060c66db4SNico Weber 
2160c66db4SNico Weber #include <elf.h>
2260c66db4SNico Weber #include <link.h>
2360c66db4SNico Weber #include <pthread.h>
2460c66db4SNico Weber #include <stdio.h>
2560c66db4SNico Weber #include <stdlib.h>
2660c66db4SNico Weber #include <signal.h>
2760c66db4SNico Weber #include <unistd.h>
2860c66db4SNico Weber #include <unwind.h>
2960c66db4SNico Weber #include <sys/time.h>
3060c66db4SNico Weber #include <sys/resource.h>
3160c66db4SNico Weber 
3260c66db4SNico Weber #include "sanitizer_common/sanitizer_common.h"
3360c66db4SNico Weber #include "sanitizer_common/sanitizer_procmaps.h"
3460c66db4SNico Weber 
3560c66db4SNico Weber namespace __msan {
3660c66db4SNico Weber 
3760c66db4SNico Weber void ReportMapRange(const char *descr, uptr beg, uptr size) {
3860c66db4SNico Weber   if (size > 0) {
3960c66db4SNico Weber     uptr end = beg + size - 1;
40*d26d5a0aSDmitry Vyukov     VPrintf(1, "%s : 0x%zx - 0x%zx\n", descr, beg, end);
4160c66db4SNico Weber   }
4260c66db4SNico Weber }
4360c66db4SNico Weber 
4460c66db4SNico Weber static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
4560c66db4SNico Weber   if (size > 0) {
4660c66db4SNico Weber     uptr end = beg + size - 1;
4760c66db4SNico Weber     if (!MemoryRangeIsAvailable(beg, end)) {
48*d26d5a0aSDmitry Vyukov       Printf("FATAL: Memory range 0x%zx - 0x%zx is not available.\n", beg, end);
4960c66db4SNico Weber       return false;
5060c66db4SNico Weber     }
5160c66db4SNico Weber   }
5260c66db4SNico Weber   return true;
5360c66db4SNico Weber }
5460c66db4SNico Weber 
5560c66db4SNico Weber static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
5660c66db4SNico Weber   if (size > 0) {
5760c66db4SNico Weber     void *addr = MmapFixedNoAccess(beg, size, name);
5860c66db4SNico Weber     if (beg == 0 && addr) {
5960c66db4SNico Weber       // Depending on the kernel configuration, we may not be able to protect
6060c66db4SNico Weber       // the page at address zero.
6160c66db4SNico Weber       uptr gap = 16 * GetPageSizeCached();
6260c66db4SNico Weber       beg += gap;
6360c66db4SNico Weber       size -= gap;
6460c66db4SNico Weber       addr = MmapFixedNoAccess(beg, size, name);
6560c66db4SNico Weber     }
6660c66db4SNico Weber     if ((uptr)addr != beg) {
6760c66db4SNico Weber       uptr end = beg + size - 1;
68*d26d5a0aSDmitry Vyukov       Printf("FATAL: Cannot protect memory range 0x%zx - 0x%zx (%s).\n", beg,
69*d26d5a0aSDmitry Vyukov              end, name);
7060c66db4SNico Weber       return false;
7160c66db4SNico Weber     }
7260c66db4SNico Weber   }
7360c66db4SNico Weber   return true;
7460c66db4SNico Weber }
7560c66db4SNico Weber 
7660c66db4SNico Weber static void CheckMemoryLayoutSanity() {
7760c66db4SNico Weber   uptr prev_end = 0;
7860c66db4SNico Weber   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
7960c66db4SNico Weber     uptr start = kMemoryLayout[i].start;
8060c66db4SNico Weber     uptr end = kMemoryLayout[i].end;
8160c66db4SNico Weber     MappingDesc::Type type = kMemoryLayout[i].type;
8260c66db4SNico Weber     CHECK_LT(start, end);
8360c66db4SNico Weber     CHECK_EQ(prev_end, start);
8460c66db4SNico Weber     CHECK(addr_is_type(start, type));
8560c66db4SNico Weber     CHECK(addr_is_type((start + end) / 2, type));
8660c66db4SNico Weber     CHECK(addr_is_type(end - 1, type));
8760c66db4SNico Weber     if (type == MappingDesc::APP) {
8860c66db4SNico Weber       uptr addr = start;
8960c66db4SNico Weber       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
9060c66db4SNico Weber       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
9160c66db4SNico Weber       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
9260c66db4SNico Weber 
9360c66db4SNico Weber       addr = (start + end) / 2;
9460c66db4SNico Weber       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
9560c66db4SNico Weber       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
9660c66db4SNico Weber       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
9760c66db4SNico Weber 
9860c66db4SNico Weber       addr = end - 1;
9960c66db4SNico Weber       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
10060c66db4SNico Weber       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
10160c66db4SNico Weber       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
10260c66db4SNico Weber     }
10360c66db4SNico Weber     prev_end = end;
10460c66db4SNico Weber   }
10560c66db4SNico Weber }
10660c66db4SNico Weber 
10760c66db4SNico Weber bool InitShadow(bool init_origins) {
10860c66db4SNico Weber   // Let user know mapping parameters first.
10960c66db4SNico Weber   VPrintf(1, "__msan_init %p\n", &__msan_init);
11060c66db4SNico Weber   for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
11160c66db4SNico Weber     VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
11260c66db4SNico Weber             kMemoryLayout[i].end - 1);
11360c66db4SNico Weber 
11460c66db4SNico Weber   CheckMemoryLayoutSanity();
11560c66db4SNico Weber 
11660c66db4SNico Weber   if (!MEM_IS_APP(&__msan_init)) {
11760c66db4SNico Weber     Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
118*d26d5a0aSDmitry Vyukov            &__msan_init);
11960c66db4SNico Weber     return false;
12060c66db4SNico Weber   }
12160c66db4SNico Weber 
12260c66db4SNico Weber   const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
12360c66db4SNico Weber 
12460c66db4SNico Weber   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
12560c66db4SNico Weber     uptr start = kMemoryLayout[i].start;
12660c66db4SNico Weber     uptr end = kMemoryLayout[i].end;
12760c66db4SNico Weber     uptr size = end - start;
12860c66db4SNico Weber     MappingDesc::Type type = kMemoryLayout[i].type;
12960c66db4SNico Weber 
13060c66db4SNico Weber     // Check if the segment should be mapped based on platform constraints.
13160c66db4SNico Weber     if (start >= maxVirtualAddress)
13260c66db4SNico Weber       continue;
13360c66db4SNico Weber 
13460c66db4SNico Weber     bool map = type == MappingDesc::SHADOW ||
13560c66db4SNico Weber                (init_origins && type == MappingDesc::ORIGIN);
13660c66db4SNico Weber     bool protect = type == MappingDesc::INVALID ||
13760c66db4SNico Weber                    (!init_origins && type == MappingDesc::ORIGIN);
13860c66db4SNico Weber     CHECK(!(map && protect));
13960c66db4SNico Weber     if (!map && !protect)
14060c66db4SNico Weber       CHECK(type == MappingDesc::APP);
14160c66db4SNico Weber     if (map) {
14260c66db4SNico Weber       if (!CheckMemoryRangeAvailability(start, size))
14360c66db4SNico Weber         return false;
144dc3388b0SEvgenii Stepanov       if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
14560c66db4SNico Weber         return false;
14660c66db4SNico Weber       if (common_flags()->use_madv_dontdump)
14760c66db4SNico Weber         DontDumpShadowMemory(start, size);
14860c66db4SNico Weber     }
14960c66db4SNico Weber     if (protect) {
15060c66db4SNico Weber       if (!CheckMemoryRangeAvailability(start, size))
15160c66db4SNico Weber         return false;
15260c66db4SNico Weber       if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
15360c66db4SNico Weber         return false;
15460c66db4SNico Weber     }
15560c66db4SNico Weber   }
15660c66db4SNico Weber 
15760c66db4SNico Weber   return true;
15860c66db4SNico Weber }
15960c66db4SNico Weber 
16060c66db4SNico Weber static void MsanAtExit(void) {
16160c66db4SNico Weber   if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
16260c66db4SNico Weber     ReportStats();
16360c66db4SNico Weber   if (msan_report_count > 0) {
16460c66db4SNico Weber     ReportAtExitStatistics();
16560c66db4SNico Weber     if (common_flags()->exitcode)
16660c66db4SNico Weber       internal__exit(common_flags()->exitcode);
16760c66db4SNico Weber   }
16860c66db4SNico Weber }
16960c66db4SNico Weber 
17060c66db4SNico Weber void InstallAtExitHandler() {
17160c66db4SNico Weber   atexit(MsanAtExit);
17260c66db4SNico Weber }
17360c66db4SNico Weber 
17460c66db4SNico Weber // ---------------------- TSD ---------------- {{{1
17560c66db4SNico Weber 
17660c66db4SNico Weber #if SANITIZER_NETBSD
17760c66db4SNico Weber // Thread Static Data cannot be used in early init on NetBSD.
17860c66db4SNico Weber // Reuse the MSan TSD API for compatibility with existing code
17960c66db4SNico Weber // with an alternative implementation.
18060c66db4SNico Weber 
18160c66db4SNico Weber static void (*tsd_destructor)(void *tsd) = nullptr;
18260c66db4SNico Weber 
18360c66db4SNico Weber struct tsd_key {
18460c66db4SNico Weber   tsd_key() : key(nullptr) {}
18560c66db4SNico Weber   ~tsd_key() {
18660c66db4SNico Weber     CHECK(tsd_destructor);
18760c66db4SNico Weber     if (key)
18860c66db4SNico Weber       (*tsd_destructor)(key);
18960c66db4SNico Weber   }
19060c66db4SNico Weber   MsanThread *key;
19160c66db4SNico Weber };
19260c66db4SNico Weber 
19360c66db4SNico Weber static thread_local struct tsd_key key;
19460c66db4SNico Weber 
19560c66db4SNico Weber void MsanTSDInit(void (*destructor)(void *tsd)) {
19660c66db4SNico Weber   CHECK(!tsd_destructor);
19760c66db4SNico Weber   tsd_destructor = destructor;
19860c66db4SNico Weber }
19960c66db4SNico Weber 
20060c66db4SNico Weber MsanThread *GetCurrentThread() {
20160c66db4SNico Weber   CHECK(tsd_destructor);
20260c66db4SNico Weber   return key.key;
20360c66db4SNico Weber }
20460c66db4SNico Weber 
20560c66db4SNico Weber void SetCurrentThread(MsanThread *tsd) {
20660c66db4SNico Weber   CHECK(tsd_destructor);
20760c66db4SNico Weber   CHECK(tsd);
20860c66db4SNico Weber   CHECK(!key.key);
20960c66db4SNico Weber   key.key = tsd;
21060c66db4SNico Weber }
21160c66db4SNico Weber 
21260c66db4SNico Weber void MsanTSDDtor(void *tsd) {
21360c66db4SNico Weber   CHECK(tsd_destructor);
21460c66db4SNico Weber   CHECK_EQ(key.key, tsd);
21560c66db4SNico Weber   key.key = nullptr;
21660c66db4SNico Weber   // Make sure that signal handler can not see a stale current thread pointer.
21760c66db4SNico Weber   atomic_signal_fence(memory_order_seq_cst);
21860c66db4SNico Weber   MsanThread::TSDDtor(tsd);
21960c66db4SNico Weber }
22060c66db4SNico Weber #else
22160c66db4SNico Weber static pthread_key_t tsd_key;
22260c66db4SNico Weber static bool tsd_key_inited = false;
22360c66db4SNico Weber 
22460c66db4SNico Weber void MsanTSDInit(void (*destructor)(void *tsd)) {
22560c66db4SNico Weber   CHECK(!tsd_key_inited);
22660c66db4SNico Weber   tsd_key_inited = true;
22760c66db4SNico Weber   CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
22860c66db4SNico Weber }
22960c66db4SNico Weber 
23060c66db4SNico Weber static THREADLOCAL MsanThread* msan_current_thread;
23160c66db4SNico Weber 
23260c66db4SNico Weber MsanThread *GetCurrentThread() {
23360c66db4SNico Weber   return msan_current_thread;
23460c66db4SNico Weber }
23560c66db4SNico Weber 
23660c66db4SNico Weber void SetCurrentThread(MsanThread *t) {
23760c66db4SNico Weber   // Make sure we do not reset the current MsanThread.
23860c66db4SNico Weber   CHECK_EQ(0, msan_current_thread);
23960c66db4SNico Weber   msan_current_thread = t;
24060c66db4SNico Weber   // Make sure that MsanTSDDtor gets called at the end.
24160c66db4SNico Weber   CHECK(tsd_key_inited);
24260c66db4SNico Weber   pthread_setspecific(tsd_key, (void *)t);
24360c66db4SNico Weber }
24460c66db4SNico Weber 
24560c66db4SNico Weber void MsanTSDDtor(void *tsd) {
24660c66db4SNico Weber   MsanThread *t = (MsanThread*)tsd;
24760c66db4SNico Weber   if (t->destructor_iterations_ > 1) {
24860c66db4SNico Weber     t->destructor_iterations_--;
24960c66db4SNico Weber     CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
25060c66db4SNico Weber     return;
25160c66db4SNico Weber   }
25260c66db4SNico Weber   msan_current_thread = nullptr;
25360c66db4SNico Weber   // Make sure that signal handler can not see a stale current thread pointer.
25460c66db4SNico Weber   atomic_signal_fence(memory_order_seq_cst);
25560c66db4SNico Weber   MsanThread::TSDDtor(tsd);
25660c66db4SNico Weber }
25760c66db4SNico Weber #endif
25860c66db4SNico Weber 
25960c66db4SNico Weber } // namespace __msan
26060c66db4SNico Weber 
26160c66db4SNico Weber #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
262