1*3cab2bb3Spatrick //===-- msan_linux.cpp ----------------------------------------------------===//
2*3cab2bb3Spatrick //
3*3cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*3cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3cab2bb3Spatrick //
7*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
8*3cab2bb3Spatrick //
9*3cab2bb3Spatrick // This file is a part of MemorySanitizer.
10*3cab2bb3Spatrick //
11*3cab2bb3Spatrick // Linux-, NetBSD- and FreeBSD-specific code.
12*3cab2bb3Spatrick //===----------------------------------------------------------------------===//
13*3cab2bb3Spatrick 
14*3cab2bb3Spatrick #include "sanitizer_common/sanitizer_platform.h"
15*3cab2bb3Spatrick #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
16*3cab2bb3Spatrick 
17*3cab2bb3Spatrick #include "msan.h"
18*3cab2bb3Spatrick #include "msan_report.h"
19*3cab2bb3Spatrick #include "msan_thread.h"
20*3cab2bb3Spatrick 
21*3cab2bb3Spatrick #include <elf.h>
22*3cab2bb3Spatrick #include <link.h>
23*3cab2bb3Spatrick #include <pthread.h>
24*3cab2bb3Spatrick #include <stdio.h>
25*3cab2bb3Spatrick #include <stdlib.h>
26*3cab2bb3Spatrick #include <signal.h>
27*3cab2bb3Spatrick #include <unistd.h>
28*3cab2bb3Spatrick #include <unwind.h>
29*3cab2bb3Spatrick #include <execinfo.h>
30*3cab2bb3Spatrick #include <sys/time.h>
31*3cab2bb3Spatrick #include <sys/resource.h>
32*3cab2bb3Spatrick 
33*3cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
34*3cab2bb3Spatrick #include "sanitizer_common/sanitizer_procmaps.h"
35*3cab2bb3Spatrick 
36*3cab2bb3Spatrick namespace __msan {
37*3cab2bb3Spatrick 
38*3cab2bb3Spatrick void ReportMapRange(const char *descr, uptr beg, uptr size) {
39*3cab2bb3Spatrick   if (size > 0) {
40*3cab2bb3Spatrick     uptr end = beg + size - 1;
41*3cab2bb3Spatrick     VPrintf(1, "%s : %p - %p\n", descr, beg, end);
42*3cab2bb3Spatrick   }
43*3cab2bb3Spatrick }
44*3cab2bb3Spatrick 
45*3cab2bb3Spatrick static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
46*3cab2bb3Spatrick   if (size > 0) {
47*3cab2bb3Spatrick     uptr end = beg + size - 1;
48*3cab2bb3Spatrick     if (!MemoryRangeIsAvailable(beg, end)) {
49*3cab2bb3Spatrick       Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
50*3cab2bb3Spatrick       return false;
51*3cab2bb3Spatrick     }
52*3cab2bb3Spatrick   }
53*3cab2bb3Spatrick   return true;
54*3cab2bb3Spatrick }
55*3cab2bb3Spatrick 
56*3cab2bb3Spatrick static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
57*3cab2bb3Spatrick   if (size > 0) {
58*3cab2bb3Spatrick     void *addr = MmapFixedNoAccess(beg, size, name);
59*3cab2bb3Spatrick     if (beg == 0 && addr) {
60*3cab2bb3Spatrick       // Depending on the kernel configuration, we may not be able to protect
61*3cab2bb3Spatrick       // the page at address zero.
62*3cab2bb3Spatrick       uptr gap = 16 * GetPageSizeCached();
63*3cab2bb3Spatrick       beg += gap;
64*3cab2bb3Spatrick       size -= gap;
65*3cab2bb3Spatrick       addr = MmapFixedNoAccess(beg, size, name);
66*3cab2bb3Spatrick     }
67*3cab2bb3Spatrick     if ((uptr)addr != beg) {
68*3cab2bb3Spatrick       uptr end = beg + size - 1;
69*3cab2bb3Spatrick       Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end,
70*3cab2bb3Spatrick              name);
71*3cab2bb3Spatrick       return false;
72*3cab2bb3Spatrick     }
73*3cab2bb3Spatrick   }
74*3cab2bb3Spatrick   return true;
75*3cab2bb3Spatrick }
76*3cab2bb3Spatrick 
77*3cab2bb3Spatrick static void CheckMemoryLayoutSanity() {
78*3cab2bb3Spatrick   uptr prev_end = 0;
79*3cab2bb3Spatrick   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
80*3cab2bb3Spatrick     uptr start = kMemoryLayout[i].start;
81*3cab2bb3Spatrick     uptr end = kMemoryLayout[i].end;
82*3cab2bb3Spatrick     MappingDesc::Type type = kMemoryLayout[i].type;
83*3cab2bb3Spatrick     CHECK_LT(start, end);
84*3cab2bb3Spatrick     CHECK_EQ(prev_end, start);
85*3cab2bb3Spatrick     CHECK(addr_is_type(start, type));
86*3cab2bb3Spatrick     CHECK(addr_is_type((start + end) / 2, type));
87*3cab2bb3Spatrick     CHECK(addr_is_type(end - 1, type));
88*3cab2bb3Spatrick     if (type == MappingDesc::APP) {
89*3cab2bb3Spatrick       uptr addr = start;
90*3cab2bb3Spatrick       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
91*3cab2bb3Spatrick       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
92*3cab2bb3Spatrick       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
93*3cab2bb3Spatrick 
94*3cab2bb3Spatrick       addr = (start + end) / 2;
95*3cab2bb3Spatrick       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
96*3cab2bb3Spatrick       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
97*3cab2bb3Spatrick       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
98*3cab2bb3Spatrick 
99*3cab2bb3Spatrick       addr = end - 1;
100*3cab2bb3Spatrick       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
101*3cab2bb3Spatrick       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
102*3cab2bb3Spatrick       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
103*3cab2bb3Spatrick     }
104*3cab2bb3Spatrick     prev_end = end;
105*3cab2bb3Spatrick   }
106*3cab2bb3Spatrick }
107*3cab2bb3Spatrick 
108*3cab2bb3Spatrick bool InitShadow(bool init_origins) {
109*3cab2bb3Spatrick   // Let user know mapping parameters first.
110*3cab2bb3Spatrick   VPrintf(1, "__msan_init %p\n", &__msan_init);
111*3cab2bb3Spatrick   for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
112*3cab2bb3Spatrick     VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
113*3cab2bb3Spatrick             kMemoryLayout[i].end - 1);
114*3cab2bb3Spatrick 
115*3cab2bb3Spatrick   CheckMemoryLayoutSanity();
116*3cab2bb3Spatrick 
117*3cab2bb3Spatrick   if (!MEM_IS_APP(&__msan_init)) {
118*3cab2bb3Spatrick     Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
119*3cab2bb3Spatrick            (uptr)&__msan_init);
120*3cab2bb3Spatrick     return false;
121*3cab2bb3Spatrick   }
122*3cab2bb3Spatrick 
123*3cab2bb3Spatrick   const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
124*3cab2bb3Spatrick 
125*3cab2bb3Spatrick   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
126*3cab2bb3Spatrick     uptr start = kMemoryLayout[i].start;
127*3cab2bb3Spatrick     uptr end = kMemoryLayout[i].end;
128*3cab2bb3Spatrick     uptr size = end - start;
129*3cab2bb3Spatrick     MappingDesc::Type type = kMemoryLayout[i].type;
130*3cab2bb3Spatrick 
131*3cab2bb3Spatrick     // Check if the segment should be mapped based on platform constraints.
132*3cab2bb3Spatrick     if (start >= maxVirtualAddress)
133*3cab2bb3Spatrick       continue;
134*3cab2bb3Spatrick 
135*3cab2bb3Spatrick     bool map = type == MappingDesc::SHADOW ||
136*3cab2bb3Spatrick                (init_origins && type == MappingDesc::ORIGIN);
137*3cab2bb3Spatrick     bool protect = type == MappingDesc::INVALID ||
138*3cab2bb3Spatrick                    (!init_origins && type == MappingDesc::ORIGIN);
139*3cab2bb3Spatrick     CHECK(!(map && protect));
140*3cab2bb3Spatrick     if (!map && !protect)
141*3cab2bb3Spatrick       CHECK(type == MappingDesc::APP);
142*3cab2bb3Spatrick     if (map) {
143*3cab2bb3Spatrick       if (!CheckMemoryRangeAvailability(start, size))
144*3cab2bb3Spatrick         return false;
145*3cab2bb3Spatrick       if (!MmapFixedNoReserve(start, size, kMemoryLayout[i].name))
146*3cab2bb3Spatrick         return false;
147*3cab2bb3Spatrick       if (common_flags()->use_madv_dontdump)
148*3cab2bb3Spatrick         DontDumpShadowMemory(start, size);
149*3cab2bb3Spatrick     }
150*3cab2bb3Spatrick     if (protect) {
151*3cab2bb3Spatrick       if (!CheckMemoryRangeAvailability(start, size))
152*3cab2bb3Spatrick         return false;
153*3cab2bb3Spatrick       if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
154*3cab2bb3Spatrick         return false;
155*3cab2bb3Spatrick     }
156*3cab2bb3Spatrick   }
157*3cab2bb3Spatrick 
158*3cab2bb3Spatrick   return true;
159*3cab2bb3Spatrick }
160*3cab2bb3Spatrick 
161*3cab2bb3Spatrick static void MsanAtExit(void) {
162*3cab2bb3Spatrick   if (flags()->print_stats && (flags()->atexit || msan_report_count > 0))
163*3cab2bb3Spatrick     ReportStats();
164*3cab2bb3Spatrick   if (msan_report_count > 0) {
165*3cab2bb3Spatrick     ReportAtExitStatistics();
166*3cab2bb3Spatrick     if (common_flags()->exitcode)
167*3cab2bb3Spatrick       internal__exit(common_flags()->exitcode);
168*3cab2bb3Spatrick   }
169*3cab2bb3Spatrick }
170*3cab2bb3Spatrick 
171*3cab2bb3Spatrick void InstallAtExitHandler() {
172*3cab2bb3Spatrick   atexit(MsanAtExit);
173*3cab2bb3Spatrick }
174*3cab2bb3Spatrick 
175*3cab2bb3Spatrick // ---------------------- TSD ---------------- {{{1
176*3cab2bb3Spatrick 
177*3cab2bb3Spatrick #if SANITIZER_NETBSD
178*3cab2bb3Spatrick // Thread Static Data cannot be used in early init on NetBSD.
179*3cab2bb3Spatrick // Reuse the MSan TSD API for compatibility with existing code
180*3cab2bb3Spatrick // with an alternative implementation.
181*3cab2bb3Spatrick 
182*3cab2bb3Spatrick static void (*tsd_destructor)(void *tsd) = nullptr;
183*3cab2bb3Spatrick 
184*3cab2bb3Spatrick struct tsd_key {
185*3cab2bb3Spatrick   tsd_key() : key(nullptr) {}
186*3cab2bb3Spatrick   ~tsd_key() {
187*3cab2bb3Spatrick     CHECK(tsd_destructor);
188*3cab2bb3Spatrick     if (key)
189*3cab2bb3Spatrick       (*tsd_destructor)(key);
190*3cab2bb3Spatrick   }
191*3cab2bb3Spatrick   MsanThread *key;
192*3cab2bb3Spatrick };
193*3cab2bb3Spatrick 
194*3cab2bb3Spatrick static thread_local struct tsd_key key;
195*3cab2bb3Spatrick 
196*3cab2bb3Spatrick void MsanTSDInit(void (*destructor)(void *tsd)) {
197*3cab2bb3Spatrick   CHECK(!tsd_destructor);
198*3cab2bb3Spatrick   tsd_destructor = destructor;
199*3cab2bb3Spatrick }
200*3cab2bb3Spatrick 
201*3cab2bb3Spatrick MsanThread *GetCurrentThread() {
202*3cab2bb3Spatrick   CHECK(tsd_destructor);
203*3cab2bb3Spatrick   return key.key;
204*3cab2bb3Spatrick }
205*3cab2bb3Spatrick 
206*3cab2bb3Spatrick void SetCurrentThread(MsanThread *tsd) {
207*3cab2bb3Spatrick   CHECK(tsd_destructor);
208*3cab2bb3Spatrick   CHECK(tsd);
209*3cab2bb3Spatrick   CHECK(!key.key);
210*3cab2bb3Spatrick   key.key = tsd;
211*3cab2bb3Spatrick }
212*3cab2bb3Spatrick 
213*3cab2bb3Spatrick void MsanTSDDtor(void *tsd) {
214*3cab2bb3Spatrick   CHECK(tsd_destructor);
215*3cab2bb3Spatrick   CHECK_EQ(key.key, tsd);
216*3cab2bb3Spatrick   key.key = nullptr;
217*3cab2bb3Spatrick   // Make sure that signal handler can not see a stale current thread pointer.
218*3cab2bb3Spatrick   atomic_signal_fence(memory_order_seq_cst);
219*3cab2bb3Spatrick   MsanThread::TSDDtor(tsd);
220*3cab2bb3Spatrick }
221*3cab2bb3Spatrick #else
222*3cab2bb3Spatrick static pthread_key_t tsd_key;
223*3cab2bb3Spatrick static bool tsd_key_inited = false;
224*3cab2bb3Spatrick 
225*3cab2bb3Spatrick void MsanTSDInit(void (*destructor)(void *tsd)) {
226*3cab2bb3Spatrick   CHECK(!tsd_key_inited);
227*3cab2bb3Spatrick   tsd_key_inited = true;
228*3cab2bb3Spatrick   CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
229*3cab2bb3Spatrick }
230*3cab2bb3Spatrick 
231*3cab2bb3Spatrick static THREADLOCAL MsanThread* msan_current_thread;
232*3cab2bb3Spatrick 
233*3cab2bb3Spatrick MsanThread *GetCurrentThread() {
234*3cab2bb3Spatrick   return msan_current_thread;
235*3cab2bb3Spatrick }
236*3cab2bb3Spatrick 
237*3cab2bb3Spatrick void SetCurrentThread(MsanThread *t) {
238*3cab2bb3Spatrick   // Make sure we do not reset the current MsanThread.
239*3cab2bb3Spatrick   CHECK_EQ(0, msan_current_thread);
240*3cab2bb3Spatrick   msan_current_thread = t;
241*3cab2bb3Spatrick   // Make sure that MsanTSDDtor gets called at the end.
242*3cab2bb3Spatrick   CHECK(tsd_key_inited);
243*3cab2bb3Spatrick   pthread_setspecific(tsd_key, (void *)t);
244*3cab2bb3Spatrick }
245*3cab2bb3Spatrick 
246*3cab2bb3Spatrick void MsanTSDDtor(void *tsd) {
247*3cab2bb3Spatrick   MsanThread *t = (MsanThread*)tsd;
248*3cab2bb3Spatrick   if (t->destructor_iterations_ > 1) {
249*3cab2bb3Spatrick     t->destructor_iterations_--;
250*3cab2bb3Spatrick     CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
251*3cab2bb3Spatrick     return;
252*3cab2bb3Spatrick   }
253*3cab2bb3Spatrick   msan_current_thread = nullptr;
254*3cab2bb3Spatrick   // Make sure that signal handler can not see a stale current thread pointer.
255*3cab2bb3Spatrick   atomic_signal_fence(memory_order_seq_cst);
256*3cab2bb3Spatrick   MsanThread::TSDDtor(tsd);
257*3cab2bb3Spatrick }
258*3cab2bb3Spatrick #endif
259*3cab2bb3Spatrick 
260*3cab2bb3Spatrick } // namespace __msan
261*3cab2bb3Spatrick 
262*3cab2bb3Spatrick #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
263