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