Home | History | Annotate | Line # | Download | only in msan
      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-, NetBSD- and FreeBSD-specific code.
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_platform.h"
     16 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
     17 
     18 #include "msan.h"
     19 #include "msan_report.h"
     20 #include "msan_thread.h"
     21 
     22 #include <elf.h>
     23 #include <link.h>
     24 #include <pthread.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <signal.h>
     28 #include <unistd.h>
     29 #include <unwind.h>
     30 #include <execinfo.h>
     31 #include <sys/time.h>
     32 #include <sys/resource.h>
     33 
     34 #include "sanitizer_common/sanitizer_common.h"
     35 #include "sanitizer_common/sanitizer_procmaps.h"
     36 
     37 namespace __msan {
     38 
     39 void ReportMapRange(const char *descr, uptr beg, uptr size) {
     40   if (size > 0) {
     41     uptr end = beg + size - 1;
     42     VPrintf(1, "%s : %p - %p\n", descr, beg, end);
     43   }
     44 }
     45 
     46 static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
     47   if (size > 0) {
     48     uptr end = beg + size - 1;
     49     if (!MemoryRangeIsAvailable(beg, end)) {
     50       Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
     51       return false;
     52     }
     53   }
     54   return true;
     55 }
     56 
     57 static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
     58   if (size > 0) {
     59     void *addr = MmapFixedNoAccess(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(beg, size, name);
     67     }
     68     if ((uptr)addr != beg) {
     69       uptr end = beg + size - 1;
     70       Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end,
     71              name);
     72       return false;
     73     }
     74   }
     75   return true;
     76 }
     77 
     78 static 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 
    109 bool InitShadow(bool init_origins) {
    110   // Let user know mapping parameters first.
    111   VPrintf(1, "__msan_init %p\n", &__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("FATAL: Code %p is out of application range. Non-PIE build?\n",
    120            (uptr)&__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(start, size))
    145         return false;
    146       if (!MmapFixedNoReserve(start, size, kMemoryLayout[i].name))
    147         return false;
    148       if (common_flags()->use_madv_dontdump)
    149         DontDumpShadowMemory(start, size);
    150     }
    151     if (protect) {
    152       if (!CheckMemoryRangeAvailability(start, size))
    153         return false;
    154       if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
    155         return false;
    156     }
    157   }
    158 
    159   return true;
    160 }
    161 
    162 static 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(common_flags()->exitcode);
    169   }
    170 }
    171 
    172 void InstallAtExitHandler() {
    173   atexit(MsanAtExit);
    174 }
    175 
    176 // ---------------------- TSD ---------------- {{{1
    177 
    178 #if SANITIZER_NETBSD || SANITIZER_FREEBSD
    179 // Thread Static Data cannot be used in early init on NetBSD and FreeBSD.
    180 // Reuse the MSan TSD API for compatibility with existing code
    181 // with an alternative implementation.
    182 
    183 static void (*tsd_destructor)(void *tsd) = nullptr;
    184 
    185 struct 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 
    195 static thread_local struct tsd_key key;
    196 
    197 void MsanTSDInit(void (*destructor)(void *tsd)) {
    198   CHECK(!tsd_destructor);
    199   tsd_destructor = destructor;
    200 }
    201 
    202 MsanThread *GetCurrentThread() {
    203   CHECK(tsd_destructor);
    204   return key.key;
    205 }
    206 
    207 void SetCurrentThread(MsanThread *tsd) {
    208   CHECK(tsd_destructor);
    209   CHECK(tsd);
    210   CHECK(!key.key);
    211   key.key = tsd;
    212 }
    213 
    214 void 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
    223 static pthread_key_t tsd_key;
    224 static bool tsd_key_inited = false;
    225 
    226 void 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 
    232 static THREADLOCAL MsanThread* msan_current_thread;
    233 
    234 MsanThread *GetCurrentThread() {
    235   return msan_current_thread;
    236 }
    237 
    238 void 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(tsd_key, (void *)t);
    245 }
    246 
    247 void 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 
    261 } // namespace __msan
    262 
    263 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
    264