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