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