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 
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 
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 
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 
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 
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 (!MmapFixedNoReserve(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 
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 
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 {
185   tsd_key() : key(nullptr) {}
186   ~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 
196 void MsanTSDInit(void (*destructor)(void *tsd)) {
197   CHECK(!tsd_destructor);
198   tsd_destructor = destructor;
199 }
200 
201 MsanThread *GetCurrentThread() {
202   CHECK(tsd_destructor);
203   return key.key;
204 }
205 
206 void SetCurrentThread(MsanThread *tsd) {
207   CHECK(tsd_destructor);
208   CHECK(tsd);
209   CHECK(!key.key);
210   key.key = tsd;
211 }
212 
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 
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 
233 MsanThread *GetCurrentThread() {
234   return msan_current_thread;
235 }
236 
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 
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