xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/msan/msan_linux.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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 
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 
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 
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 
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 
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 
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 
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 {
22868d75effSDimitry Andric   tsd_key() : key(nullptr) {}
22968d75effSDimitry 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 
23968d75effSDimitry Andric void MsanTSDInit(void (*destructor)(void *tsd)) {
24068d75effSDimitry Andric   CHECK(!tsd_destructor);
24168d75effSDimitry Andric   tsd_destructor = destructor;
24268d75effSDimitry Andric }
24368d75effSDimitry Andric 
24468d75effSDimitry Andric MsanThread *GetCurrentThread() {
24568d75effSDimitry Andric   CHECK(tsd_destructor);
24668d75effSDimitry Andric   return key.key;
24768d75effSDimitry Andric }
24868d75effSDimitry Andric 
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 
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 
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 
27668d75effSDimitry Andric MsanThread *GetCurrentThread() {
27768d75effSDimitry Andric   return msan_current_thread;
27868d75effSDimitry Andric }
27968d75effSDimitry Andric 
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 
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 
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 
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 
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