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