168d75effSDimitry Andric //===-- msan_linux.cpp ----------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of MemorySanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Linux-, NetBSD- and FreeBSD-specific code.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
1568d75effSDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
1668d75effSDimitry Andric
1768d75effSDimitry Andric # include <elf.h>
1868d75effSDimitry Andric # include <link.h>
1968d75effSDimitry Andric # include <pthread.h>
205f757f3fSDimitry Andric # include <signal.h>
2168d75effSDimitry Andric # include <stdio.h>
2268d75effSDimitry Andric # include <stdlib.h>
23439352acSDimitry Andric # if SANITIZER_LINUX
24439352acSDimitry Andric # include <sys/personality.h>
25439352acSDimitry Andric # endif
265f757f3fSDimitry Andric # include <sys/resource.h>
275f757f3fSDimitry Andric # include <sys/time.h>
2868d75effSDimitry Andric # include <unistd.h>
2968d75effSDimitry Andric # include <unwind.h>
3068d75effSDimitry Andric
315f757f3fSDimitry Andric # include "msan.h"
325f757f3fSDimitry Andric # include "msan_allocator.h"
335f757f3fSDimitry Andric # include "msan_chained_origin_depot.h"
345f757f3fSDimitry Andric # include "msan_report.h"
355f757f3fSDimitry Andric # include "msan_thread.h"
3668d75effSDimitry Andric # include "sanitizer_common/sanitizer_common.h"
3768d75effSDimitry Andric # include "sanitizer_common/sanitizer_procmaps.h"
385f757f3fSDimitry Andric # include "sanitizer_common/sanitizer_stackdepot.h"
3968d75effSDimitry Andric
4068d75effSDimitry Andric namespace __msan {
4168d75effSDimitry Andric
ReportMapRange(const char * descr,uptr beg,uptr size)4268d75effSDimitry Andric void ReportMapRange(const char *descr, uptr beg, uptr size) {
4368d75effSDimitry Andric if (size > 0) {
4468d75effSDimitry Andric uptr end = beg + size - 1;
45*0fca6ea1SDimitry Andric VPrintf(1, "%s : %p-%p\n", descr, (void *)beg, (void *)end);
4668d75effSDimitry Andric }
4768d75effSDimitry Andric }
4868d75effSDimitry Andric
CheckMemoryRangeAvailability(uptr beg,uptr size,bool verbose)49439352acSDimitry Andric static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {
5068d75effSDimitry Andric if (size > 0) {
5168d75effSDimitry Andric uptr end = beg + size - 1;
5268d75effSDimitry Andric if (!MemoryRangeIsAvailable(beg, end)) {
53439352acSDimitry Andric if (verbose)
54*0fca6ea1SDimitry Andric Printf("FATAL: MemorySanitizer: Shadow range %p-%p is not available.\n",
55*0fca6ea1SDimitry Andric (void *)beg, (void *)end);
5668d75effSDimitry Andric return false;
5768d75effSDimitry Andric }
5868d75effSDimitry Andric }
5968d75effSDimitry Andric return true;
6068d75effSDimitry Andric }
6168d75effSDimitry Andric
ProtectMemoryRange(uptr beg,uptr size,const char * name)6268d75effSDimitry Andric static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
6368d75effSDimitry Andric if (size > 0) {
6468d75effSDimitry Andric void *addr = MmapFixedNoAccess(beg, size, name);
6568d75effSDimitry Andric if (beg == 0 && addr) {
6668d75effSDimitry Andric // Depending on the kernel configuration, we may not be able to protect
6768d75effSDimitry Andric // the page at address zero.
6868d75effSDimitry Andric uptr gap = 16 * GetPageSizeCached();
6968d75effSDimitry Andric beg += gap;
7068d75effSDimitry Andric size -= gap;
7168d75effSDimitry Andric addr = MmapFixedNoAccess(beg, size, name);
7268d75effSDimitry Andric }
7368d75effSDimitry Andric if ((uptr)addr != beg) {
7468d75effSDimitry Andric uptr end = beg + size - 1;
75*0fca6ea1SDimitry Andric Printf(
76*0fca6ea1SDimitry Andric "FATAL: MemorySanitizer: Cannot protect memory range %p-%p (%s).\n",
77*0fca6ea1SDimitry Andric (void *)beg, (void *)end, name);
7868d75effSDimitry Andric return false;
7968d75effSDimitry Andric }
8068d75effSDimitry Andric }
8168d75effSDimitry Andric return true;
8268d75effSDimitry Andric }
8368d75effSDimitry Andric
CheckMemoryLayoutSanity()8468d75effSDimitry Andric static void CheckMemoryLayoutSanity() {
8568d75effSDimitry Andric uptr prev_end = 0;
8668d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
8768d75effSDimitry Andric uptr start = kMemoryLayout[i].start;
8868d75effSDimitry Andric uptr end = kMemoryLayout[i].end;
8968d75effSDimitry Andric MappingDesc::Type type = kMemoryLayout[i].type;
9068d75effSDimitry Andric CHECK_LT(start, end);
9168d75effSDimitry Andric CHECK_EQ(prev_end, start);
9268d75effSDimitry Andric CHECK(addr_is_type(start, type));
9368d75effSDimitry Andric CHECK(addr_is_type((start + end) / 2, type));
9468d75effSDimitry Andric CHECK(addr_is_type(end - 1, type));
95439352acSDimitry Andric if (type == MappingDesc::APP || type == MappingDesc::ALLOCATOR) {
9668d75effSDimitry Andric uptr addr = start;
9768d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
9868d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
9968d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
10068d75effSDimitry Andric
10168d75effSDimitry Andric addr = (start + end) / 2;
10268d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
10368d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
10468d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
10568d75effSDimitry Andric
10668d75effSDimitry Andric addr = end - 1;
10768d75effSDimitry Andric CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
10868d75effSDimitry Andric CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
10968d75effSDimitry Andric CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
11068d75effSDimitry Andric }
11168d75effSDimitry Andric prev_end = end;
11268d75effSDimitry Andric }
11368d75effSDimitry Andric }
11468d75effSDimitry Andric
InitShadow(bool init_origins,bool dry_run)115439352acSDimitry Andric static bool InitShadow(bool init_origins, bool dry_run) {
11668d75effSDimitry Andric // Let user know mapping parameters first.
117349cc55cSDimitry Andric VPrintf(1, "__msan_init %p\n", reinterpret_cast<void *>(&__msan_init));
11868d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
11968d75effSDimitry Andric VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
12068d75effSDimitry Andric kMemoryLayout[i].end - 1);
12168d75effSDimitry Andric
12268d75effSDimitry Andric CheckMemoryLayoutSanity();
12368d75effSDimitry Andric
12468d75effSDimitry Andric if (!MEM_IS_APP(&__msan_init)) {
125439352acSDimitry Andric if (!dry_run)
12668d75effSDimitry Andric Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
127349cc55cSDimitry Andric reinterpret_cast<void *>(&__msan_init));
12868d75effSDimitry Andric return false;
12968d75effSDimitry Andric }
13068d75effSDimitry Andric
13168d75effSDimitry Andric const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
13268d75effSDimitry Andric
13368d75effSDimitry Andric for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
13468d75effSDimitry Andric uptr start = kMemoryLayout[i].start;
13568d75effSDimitry Andric uptr end = kMemoryLayout[i].end;
13668d75effSDimitry Andric uptr size = end - start;
13768d75effSDimitry Andric MappingDesc::Type type = kMemoryLayout[i].type;
13868d75effSDimitry Andric
13968d75effSDimitry Andric // Check if the segment should be mapped based on platform constraints.
14068d75effSDimitry Andric if (start >= maxVirtualAddress)
14168d75effSDimitry Andric continue;
14268d75effSDimitry Andric
14368d75effSDimitry Andric bool map = type == MappingDesc::SHADOW ||
14468d75effSDimitry Andric (init_origins && type == MappingDesc::ORIGIN);
14568d75effSDimitry Andric bool protect = type == MappingDesc::INVALID ||
14668d75effSDimitry Andric (!init_origins && type == MappingDesc::ORIGIN);
14768d75effSDimitry Andric CHECK(!(map && protect));
148439352acSDimitry Andric if (!map && !protect) {
149439352acSDimitry Andric CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
150439352acSDimitry Andric
151439352acSDimitry Andric if (dry_run && type == MappingDesc::ALLOCATOR &&
152439352acSDimitry Andric !CheckMemoryRangeAvailability(start, size, !dry_run))
153439352acSDimitry Andric return false;
154439352acSDimitry Andric }
15568d75effSDimitry Andric if (map) {
156439352acSDimitry Andric if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
15768d75effSDimitry Andric return false;
158439352acSDimitry Andric if (!dry_run &&
159439352acSDimitry Andric !MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
16068d75effSDimitry Andric return false;
161439352acSDimitry Andric if (!dry_run && common_flags()->use_madv_dontdump)
16268d75effSDimitry Andric DontDumpShadowMemory(start, size);
16368d75effSDimitry Andric }
16468d75effSDimitry Andric if (protect) {
165439352acSDimitry Andric if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
16668d75effSDimitry Andric return false;
167439352acSDimitry Andric if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))
16868d75effSDimitry Andric return false;
16968d75effSDimitry Andric }
17068d75effSDimitry Andric }
17168d75effSDimitry Andric
17268d75effSDimitry Andric return true;
17368d75effSDimitry Andric }
17468d75effSDimitry Andric
InitShadowWithReExec(bool init_origins)175439352acSDimitry Andric bool InitShadowWithReExec(bool init_origins) {
176439352acSDimitry Andric // Start with dry run: check layout is ok, but don't print warnings because
177439352acSDimitry Andric // warning messages will cause tests to fail (even if we successfully re-exec
178439352acSDimitry Andric // after the warning).
179*0fca6ea1SDimitry Andric bool success = InitShadow(init_origins, true);
180439352acSDimitry Andric if (!success) {
181439352acSDimitry Andric # if SANITIZER_LINUX
182439352acSDimitry Andric // Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.
183439352acSDimitry Andric int old_personality = personality(0xffffffff);
184439352acSDimitry Andric bool aslr_on =
185439352acSDimitry Andric (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
186439352acSDimitry Andric
187439352acSDimitry Andric if (aslr_on) {
188439352acSDimitry Andric VReport(1,
189439352acSDimitry Andric "WARNING: MemorySanitizer: memory layout is incompatible, "
190439352acSDimitry Andric "possibly due to high-entropy ASLR.\n"
191439352acSDimitry Andric "Re-execing with fixed virtual address space.\n"
192439352acSDimitry Andric "N.B. reducing ASLR entropy is preferable.\n");
193439352acSDimitry Andric CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
194439352acSDimitry Andric ReExec();
195439352acSDimitry Andric }
196439352acSDimitry Andric # endif
197439352acSDimitry Andric }
198439352acSDimitry Andric
199439352acSDimitry Andric // The earlier dry run didn't actually map or protect anything. Run again in
200439352acSDimitry Andric // non-dry run mode.
201*0fca6ea1SDimitry Andric return success && InitShadow(init_origins, false);
202439352acSDimitry Andric }
203439352acSDimitry Andric
MsanAtExit(void)20468d75effSDimitry Andric static void MsanAtExit(void) {
20568d75effSDimitry Andric if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
20668d75effSDimitry Andric ReportStats();
20768d75effSDimitry Andric if (msan_report_count > 0) {
20868d75effSDimitry Andric ReportAtExitStatistics();
20968d75effSDimitry Andric if (common_flags()->exitcode)
21068d75effSDimitry Andric internal__exit(common_flags()->exitcode);
21168d75effSDimitry Andric }
21268d75effSDimitry Andric }
21368d75effSDimitry Andric
InstallAtExitHandler()21468d75effSDimitry Andric void InstallAtExitHandler() {
21568d75effSDimitry Andric atexit(MsanAtExit);
21668d75effSDimitry Andric }
21768d75effSDimitry Andric
21868d75effSDimitry Andric // ---------------------- TSD ---------------- {{{1
21968d75effSDimitry Andric
22068d75effSDimitry Andric #if SANITIZER_NETBSD
22168d75effSDimitry Andric // Thread Static Data cannot be used in early init on NetBSD.
22268d75effSDimitry Andric // Reuse the MSan TSD API for compatibility with existing code
22368d75effSDimitry Andric // with an alternative implementation.
22468d75effSDimitry Andric
22568d75effSDimitry Andric static void (*tsd_destructor)(void *tsd) = nullptr;
22668d75effSDimitry Andric
22768d75effSDimitry Andric struct tsd_key {
tsd_key__msan::tsd_key22868d75effSDimitry Andric tsd_key() : key(nullptr) {}
~tsd_key__msan::tsd_key22968d75effSDimitry Andric ~tsd_key() {
23068d75effSDimitry Andric CHECK(tsd_destructor);
23168d75effSDimitry Andric if (key)
23268d75effSDimitry Andric (*tsd_destructor)(key);
23368d75effSDimitry Andric }
23468d75effSDimitry Andric MsanThread *key;
23568d75effSDimitry Andric };
23668d75effSDimitry Andric
23768d75effSDimitry Andric static thread_local struct tsd_key key;
23868d75effSDimitry Andric
MsanTSDInit(void (* destructor)(void * tsd))23968d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) {
24068d75effSDimitry Andric CHECK(!tsd_destructor);
24168d75effSDimitry Andric tsd_destructor = destructor;
24268d75effSDimitry Andric }
24368d75effSDimitry Andric
GetCurrentThread()24468d75effSDimitry Andric MsanThread *GetCurrentThread() {
24568d75effSDimitry Andric CHECK(tsd_destructor);
24668d75effSDimitry Andric return key.key;
24768d75effSDimitry Andric }
24868d75effSDimitry Andric
SetCurrentThread(MsanThread * tsd)24968d75effSDimitry Andric void SetCurrentThread(MsanThread *tsd) {
25068d75effSDimitry Andric CHECK(tsd_destructor);
25168d75effSDimitry Andric CHECK(tsd);
25268d75effSDimitry Andric CHECK(!key.key);
25368d75effSDimitry Andric key.key = tsd;
25468d75effSDimitry Andric }
25568d75effSDimitry Andric
MsanTSDDtor(void * tsd)25668d75effSDimitry Andric void MsanTSDDtor(void *tsd) {
25768d75effSDimitry Andric CHECK(tsd_destructor);
25868d75effSDimitry Andric CHECK_EQ(key.key, tsd);
25968d75effSDimitry Andric key.key = nullptr;
26068d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer.
26168d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst);
26268d75effSDimitry Andric MsanThread::TSDDtor(tsd);
26368d75effSDimitry Andric }
26468d75effSDimitry Andric #else
26568d75effSDimitry Andric static pthread_key_t tsd_key;
26668d75effSDimitry Andric static bool tsd_key_inited = false;
26768d75effSDimitry Andric
MsanTSDInit(void (* destructor)(void * tsd))26868d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) {
26968d75effSDimitry Andric CHECK(!tsd_key_inited);
27068d75effSDimitry Andric tsd_key_inited = true;
27168d75effSDimitry Andric CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
27268d75effSDimitry Andric }
27368d75effSDimitry Andric
27468d75effSDimitry Andric static THREADLOCAL MsanThread* msan_current_thread;
27568d75effSDimitry Andric
GetCurrentThread()27668d75effSDimitry Andric MsanThread *GetCurrentThread() {
27768d75effSDimitry Andric return msan_current_thread;
27868d75effSDimitry Andric }
27968d75effSDimitry Andric
SetCurrentThread(MsanThread * t)28068d75effSDimitry Andric void SetCurrentThread(MsanThread *t) {
28168d75effSDimitry Andric // Make sure we do not reset the current MsanThread.
28268d75effSDimitry Andric CHECK_EQ(0, msan_current_thread);
28368d75effSDimitry Andric msan_current_thread = t;
28468d75effSDimitry Andric // Make sure that MsanTSDDtor gets called at the end.
28568d75effSDimitry Andric CHECK(tsd_key_inited);
28668d75effSDimitry Andric pthread_setspecific(tsd_key, (void *)t);
28768d75effSDimitry Andric }
28868d75effSDimitry Andric
MsanTSDDtor(void * tsd)28968d75effSDimitry Andric void MsanTSDDtor(void *tsd) {
29068d75effSDimitry Andric MsanThread *t = (MsanThread*)tsd;
29168d75effSDimitry Andric if (t->destructor_iterations_ > 1) {
29268d75effSDimitry Andric t->destructor_iterations_--;
29368d75effSDimitry Andric CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
29468d75effSDimitry Andric return;
29568d75effSDimitry Andric }
296*0fca6ea1SDimitry Andric ScopedBlockSignals block(nullptr);
29768d75effSDimitry Andric msan_current_thread = nullptr;
29868d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer.
29968d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst);
30068d75effSDimitry Andric MsanThread::TSDDtor(tsd);
30168d75effSDimitry Andric }
30268d75effSDimitry Andric # endif
30368d75effSDimitry Andric
BeforeFork()304cb14a3feSDimitry Andric static void BeforeFork() {
3055f757f3fSDimitry Andric // Usually we lock ThreadRegistry, but msan does not have one.
3065f757f3fSDimitry Andric LockAllocator();
307cb14a3feSDimitry Andric StackDepotLockBeforeFork();
308cb14a3feSDimitry Andric ChainedOriginDepotBeforeFork();
309cb14a3feSDimitry Andric }
310cb14a3feSDimitry Andric
AfterFork(bool fork_child)311cb14a3feSDimitry Andric static void AfterFork(bool fork_child) {
312cb14a3feSDimitry Andric ChainedOriginDepotAfterFork(fork_child);
313cb14a3feSDimitry Andric StackDepotUnlockAfterFork(fork_child);
3145f757f3fSDimitry Andric UnlockAllocator();
3155f757f3fSDimitry Andric // Usually we unlock ThreadRegistry, but msan does not have one.
316cb14a3feSDimitry Andric }
317cb14a3feSDimitry Andric
InstallAtForkHandler()318cb14a3feSDimitry Andric void InstallAtForkHandler() {
319cb14a3feSDimitry Andric pthread_atfork(
320cb14a3feSDimitry Andric &BeforeFork, []() { AfterFork(/* fork_child= */ false); },
321cb14a3feSDimitry Andric []() { AfterFork(/* fork_child= */ true); });
3225f757f3fSDimitry Andric }
3235f757f3fSDimitry Andric
32468d75effSDimitry Andric } // namespace __msan
32568d75effSDimitry Andric
32668d75effSDimitry Andric #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
327