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-specific code. 13 //===----------------------------------------------------------------------===// 14 15 #ifdef __linux__ 16 17 #include "msan.h" 18 19 #include <algorithm> 20 #include <elf.h> 21 #include <link.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <signal.h> 25 #include <unistd.h> 26 #include <unwind.h> 27 #include <execinfo.h> 28 #include <sys/time.h> 29 #include <sys/resource.h> 30 31 #include "sanitizer_common/sanitizer_common.h" 32 #include "sanitizer_common/sanitizer_procmaps.h" 33 34 namespace __msan { 35 36 static const uptr kMemBeg = 0x600000000000; 37 static const uptr kMemEnd = 0x7fffffffffff; 38 static const uptr kShadowBeg = MEM_TO_SHADOW(kMemBeg); 39 static const uptr kShadowEnd = MEM_TO_SHADOW(kMemEnd); 40 static const uptr kBad1Beg = 0x100000000; // 4G 41 static const uptr kBad1End = kShadowBeg - 1; 42 static const uptr kBad2Beg = kShadowEnd + 1; 43 static const uptr kBad2End = kMemBeg - 1; 44 static const uptr kOriginsBeg = kBad2Beg; 45 static const uptr kOriginsEnd = kBad2End; 46 47 bool InitShadow(bool prot1, bool prot2, bool map_shadow, bool init_origins) { 48 if (flags()->verbosity) { 49 Printf("__msan_init %p\n", &__msan_init); 50 Printf("Memory : %p %p\n", kMemBeg, kMemEnd); 51 Printf("Bad2 : %p %p\n", kBad2Beg, kBad2End); 52 Printf("Origins : %p %p\n", kOriginsBeg, kOriginsEnd); 53 Printf("Shadow : %p %p\n", kShadowBeg, kShadowEnd); 54 Printf("Bad1 : %p %p\n", kBad1Beg, kBad1End); 55 } 56 57 if (!MemoryRangeIsAvailable(kShadowBeg, 58 init_origins ? kOriginsEnd : kShadowEnd)) { 59 Printf("FATAL: Shadow memory range is not available.\n"); 60 return false; 61 } 62 63 if (prot1 && !Mprotect(kBad1Beg, kBad1End - kBad1Beg)) 64 return false; 65 if (prot2 && !Mprotect(kBad2Beg, kBad2End - kBad2Beg)) 66 return false; 67 if (map_shadow) { 68 void *shadow = MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg); 69 if (shadow != (void*)kShadowBeg) return false; 70 } 71 if (init_origins) { 72 void *origins = MmapFixedNoReserve(kOriginsBeg, kOriginsEnd - kOriginsBeg); 73 if (origins != (void*)kOriginsBeg) return false; 74 } 75 return true; 76 } 77 78 void MsanDie() { 79 _exit(flags()->exit_code); 80 } 81 82 static void MsanAtExit(void) { 83 if (msan_report_count > 0) { 84 ReportAtExitStatistics(); 85 if (flags()->exit_code) 86 _exit(flags()->exit_code); 87 } 88 } 89 90 void InstallAtExitHandler() { 91 atexit(MsanAtExit); 92 } 93 94 void UnpoisonMappedDSO(link_map *map) { 95 typedef ElfW(Phdr) Elf_Phdr; 96 typedef ElfW(Ehdr) Elf_Ehdr; 97 char *base = (char *)map->l_addr; 98 Elf_Ehdr *ehdr = (Elf_Ehdr *)base; 99 char *phdrs = base + ehdr->e_phoff; 100 char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; 101 102 // Find the segment with the minimum base so we can "relocate" the p_vaddr 103 // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC 104 // objects have a non-zero base. 105 uptr preferred_base = ~0ULL; 106 for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { 107 Elf_Phdr *phdr = (Elf_Phdr *)iter; 108 if (phdr->p_type == PT_LOAD) 109 preferred_base = std::min(preferred_base, (uptr)phdr->p_vaddr); 110 } 111 112 // Compute the delta from the real base to get a relocation delta. 113 sptr delta = (uptr)base - preferred_base; 114 // Now we can figure out what the loader really mapped. 115 for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { 116 Elf_Phdr *phdr = (Elf_Phdr *)iter; 117 if (phdr->p_type == PT_LOAD) { 118 uptr seg_start = phdr->p_vaddr + delta; 119 uptr seg_end = seg_start + phdr->p_memsz; 120 // None of these values are aligned. We consider the ragged edges of the 121 // load command as defined, since they are mapped from the file. 122 seg_start = RoundDownTo(seg_start, GetPageSizeCached()); 123 seg_end = RoundUpTo(seg_end, GetPageSizeCached()); 124 __msan_unpoison((void *)seg_start, seg_end - seg_start); 125 } 126 } 127 } 128 129 } // namespace __msan 130 131 #endif // __linux__ 132