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
ReportMapRange(const char * descr,uptr beg,uptr size)3760c66db4SNico Weber void ReportMapRange(const char *descr, uptr beg, uptr size) {
3860c66db4SNico Weber if (size > 0) {
3960c66db4SNico Weber uptr end = beg + size - 1;
40d26d5a0aSDmitry Vyukov VPrintf(1, "%s : 0x%zx - 0x%zx\n", descr, beg, end);
4160c66db4SNico Weber }
4260c66db4SNico Weber }
4360c66db4SNico Weber
CheckMemoryRangeAvailability(uptr beg,uptr size)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)) {
48d26d5a0aSDmitry 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
ProtectMemoryRange(uptr beg,uptr size,const char * name)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;
68d26d5a0aSDmitry Vyukov Printf("FATAL: Cannot protect memory range 0x%zx - 0x%zx (%s).\n", beg,
69d26d5a0aSDmitry Vyukov end, name);
7060c66db4SNico Weber return false;
7160c66db4SNico Weber }
7260c66db4SNico Weber }
7360c66db4SNico Weber return true;
7460c66db4SNico Weber }
7560c66db4SNico Weber
CheckMemoryLayoutSanity()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
InitShadow(bool init_origins)10760c66db4SNico Weber bool InitShadow(bool init_origins) {
10860c66db4SNico Weber // Let user know mapping parameters first.
109*db0af393SVitaly Buka VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__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*db0af393SVitaly Buka reinterpret_cast<void *>(&__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
MsanAtExit(void)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
InstallAtExitHandler()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 {
tsd_key__msan::tsd_key18460c66db4SNico Weber tsd_key() : key(nullptr) {}
~tsd_key__msan::tsd_key18560c66db4SNico 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
MsanTSDInit(void (* destructor)(void * tsd))19560c66db4SNico Weber void MsanTSDInit(void (*destructor)(void *tsd)) {
19660c66db4SNico Weber CHECK(!tsd_destructor);
19760c66db4SNico Weber tsd_destructor = destructor;
19860c66db4SNico Weber }
19960c66db4SNico Weber
GetCurrentThread()20060c66db4SNico Weber MsanThread *GetCurrentThread() {
20160c66db4SNico Weber CHECK(tsd_destructor);
20260c66db4SNico Weber return key.key;
20360c66db4SNico Weber }
20460c66db4SNico Weber
SetCurrentThread(MsanThread * tsd)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
MsanTSDDtor(void * tsd)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
MsanTSDInit(void (* destructor)(void * tsd))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
GetCurrentThread()23260c66db4SNico Weber MsanThread *GetCurrentThread() {
23360c66db4SNico Weber return msan_current_thread;
23460c66db4SNico Weber }
23560c66db4SNico Weber
SetCurrentThread(MsanThread * t)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
MsanTSDDtor(void * tsd)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