1//===-- msan_linux.cc -----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of MemorySanitizer.
11//
12// Linux- and FreeBSD-specific code.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_common/sanitizer_platform.h"
16#if SANITIZER_FREEBSD || SANITIZER_LINUX
17
18#include "msan.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
36namespace __msan {
37
38void 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
45static 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
56static 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.\n", beg, end);
70      return false;
71    }
72  }
73  return true;
74}
75
76static 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
107bool InitShadow(bool init_origins) {
108  // Let user know mapping parameters first.
109  VPrintf(1, "__msan_init %p\n", &__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           (uptr)&__msan_init);
119    return false;
120  }
121
122  const uptr maxVirtualAddress = GetMaxVirtualAddress();
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 ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start)
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
160static 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
170void InstallAtExitHandler() {
171  atexit(MsanAtExit);
172}
173
174// ---------------------- TSD ---------------- {{{1
175
176static pthread_key_t tsd_key;
177static bool tsd_key_inited = false;
178
179void MsanTSDInit(void (*destructor)(void *tsd)) {
180  CHECK(!tsd_key_inited);
181  tsd_key_inited = true;
182  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
183}
184
185static THREADLOCAL MsanThread* msan_current_thread;
186
187MsanThread *GetCurrentThread() {
188  return msan_current_thread;
189}
190
191void SetCurrentThread(MsanThread *t) {
192  // Make sure we do not reset the current MsanThread.
193  CHECK_EQ(0, msan_current_thread);
194  msan_current_thread = t;
195  // Make sure that MsanTSDDtor gets called at the end.
196  CHECK(tsd_key_inited);
197  pthread_setspecific(tsd_key, (void *)t);
198}
199
200void MsanTSDDtor(void *tsd) {
201  MsanThread *t = (MsanThread*)tsd;
202  if (t->destructor_iterations_ > 1) {
203    t->destructor_iterations_--;
204    CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
205    return;
206  }
207  msan_current_thread = nullptr;
208  // Make sure that signal handler can not see a stale current thread pointer.
209  atomic_signal_fence(memory_order_seq_cst);
210  MsanThread::TSDDtor(tsd);
211}
212
213} // namespace __msan
214
215#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
216