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