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

source code of compiler-rt/lib/msan/msan_linux.cpp