Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 1 | //===-- msan_poisoning.cc ---------------------------------------*- C++ -*-===// |
| 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 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "msan_poisoning.h" |
| 15 | |
| 16 | #include "interception/interception.h" |
| 17 | #include "msan_origin.h" |
| 18 | #include "sanitizer_common/sanitizer_common.h" |
| 19 | |
| 20 | DECLARE_REAL(void *, memset, void *dest, int c, uptr n) |
| 21 | DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) |
| 22 | DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n) |
| 23 | |
| 24 | namespace __msan { |
| 25 | |
| 26 | u32 GetOriginIfPoisoned(uptr addr, uptr size) { |
| 27 | unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr); |
| 28 | for (uptr i = 0; i < size; ++i) |
| 29 | if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL); |
| 30 | return 0; |
| 31 | } |
| 32 | |
| 33 | void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, |
| 34 | u32 src_origin) { |
| 35 | uptr dst_s = MEM_TO_SHADOW(addr); |
| 36 | uptr src_s = src_shadow; |
| 37 | uptr src_s_end = src_s + size; |
| 38 | |
| 39 | for (; src_s < src_s_end; ++dst_s, ++src_s) |
| 40 | if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin; |
| 41 | } |
| 42 | |
| 43 | void CopyOrigin(const void *dst, const void *src, uptr size, |
| 44 | StackTrace *stack) { |
| 45 | if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return; |
| 46 | |
| 47 | uptr d = (uptr)dst; |
| 48 | uptr beg = d & ~3UL; |
| 49 | // Copy left unaligned origin if that memory is poisoned. |
| 50 | if (beg < d) { |
| 51 | u32 o = GetOriginIfPoisoned((uptr)src, d - beg); |
| 52 | if (o) { |
| 53 | if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); |
| 54 | *(u32 *)MEM_TO_ORIGIN(beg) = o; |
| 55 | } |
| 56 | beg += 4; |
| 57 | } |
| 58 | |
| 59 | uptr end = (d + size) & ~3UL; |
| 60 | // If both ends fall into the same 4-byte slot, we are done. |
| 61 | if (end < beg) return; |
| 62 | |
| 63 | // Copy right unaligned origin if that memory is poisoned. |
| 64 | if (end < d + size) { |
| 65 | u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end); |
| 66 | if (o) { |
| 67 | if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); |
| 68 | *(u32 *)MEM_TO_ORIGIN(end) = o; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | if (beg < end) { |
| 73 | // Align src up. |
| 74 | uptr s = ((uptr)src + 3) & ~3UL; |
| 75 | // FIXME: factor out to msan_copy_origin_aligned |
| 76 | if (__msan_get_track_origins() > 1) { |
| 77 | u32 *src = (u32 *)MEM_TO_ORIGIN(s); |
| 78 | u32 *src_s = (u32 *)MEM_TO_SHADOW(s); |
| 79 | u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg)); |
| 80 | u32 *dst = (u32 *)MEM_TO_ORIGIN(beg); |
| 81 | u32 src_o = 0; |
| 82 | u32 dst_o = 0; |
| 83 | for (; src < src_end; ++src, ++src_s, ++dst) { |
| 84 | if (!*src_s) continue; |
| 85 | if (*src != src_o) { |
| 86 | src_o = *src; |
| 87 | dst_o = ChainOrigin(src_o, stack); |
| 88 | } |
| 89 | *dst = dst_o; |
| 90 | } |
| 91 | } else { |
| 92 | REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), |
| 93 | end - beg); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | void MoveShadowAndOrigin(const void *dst, const void *src, uptr size, |
| 99 | StackTrace *stack) { |
| 100 | if (!MEM_IS_APP(dst)) return; |
| 101 | if (!MEM_IS_APP(src)) return; |
| 102 | if (src == dst) return; |
| 103 | REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst), |
| 104 | (void *)MEM_TO_SHADOW((uptr)src), size); |
| 105 | if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack); |
| 106 | } |
| 107 | |
| 108 | void CopyShadowAndOrigin(const void *dst, const void *src, uptr size, |
| 109 | StackTrace *stack) { |
| 110 | if (!MEM_IS_APP(dst)) return; |
| 111 | if (!MEM_IS_APP(src)) return; |
| 112 | REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst), |
| 113 | (void *)MEM_TO_SHADOW((uptr)src), size); |
| 114 | if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack); |
| 115 | } |
| 116 | |
| 117 | void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) { |
| 118 | REAL(memcpy)(dst, src, size); |
| 119 | CopyShadowAndOrigin(dst, src, size, stack); |
| 120 | } |
| 121 | |
| 122 | void SetShadow(const void *ptr, uptr size, u8 value) { |
| 123 | uptr PageSize = GetPageSizeCached(); |
| 124 | uptr shadow_beg = MEM_TO_SHADOW(ptr); |
| 125 | uptr shadow_end = MEM_TO_SHADOW((uptr)ptr + size); |
| 126 | if (value || |
| 127 | shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { |
| 128 | REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg); |
| 129 | } else { |
| 130 | uptr page_beg = RoundUpTo(shadow_beg, PageSize); |
| 131 | uptr page_end = RoundDownTo(shadow_end, PageSize); |
| 132 | |
| 133 | if (page_beg >= page_end) { |
| 134 | REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); |
| 135 | } else { |
| 136 | if (page_beg != shadow_beg) { |
| 137 | REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); |
| 138 | } |
| 139 | if (page_end != shadow_end) { |
| 140 | REAL(memset)((void *)page_end, 0, shadow_end - page_end); |
| 141 | } |
| 142 | MmapFixedNoReserve(page_beg, page_end - page_beg); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | void SetOrigin(const void *dst, uptr size, u32 origin) { |
| 148 | // Origin mapping is 4 bytes per 4 bytes of application memory. |
| 149 | // Here we extend the range such that its left and right bounds are both |
| 150 | // 4 byte aligned. |
| 151 | uptr x = MEM_TO_ORIGIN((uptr)dst); |
| 152 | uptr beg = x & ~3UL; // align down. |
| 153 | uptr end = (x + size + 3) & ~3UL; // align up. |
| 154 | u64 origin64 = ((u64)origin << 32) | origin; |
| 155 | // This is like memset, but the value is 32-bit. We unroll by 2 to write |
| 156 | // 64 bits at once. May want to unroll further to get 128-bit stores. |
| 157 | if (beg & 7ULL) { |
| 158 | *(u32 *)beg = origin; |
| 159 | beg += 4; |
| 160 | } |
| 161 | for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64; |
| 162 | if (end & 7ULL) *(u32 *)(end - 4) = origin; |
| 163 | } |
| 164 | |
| 165 | void PoisonMemory(const void *dst, uptr size, StackTrace *stack) { |
| 166 | SetShadow(dst, size, (u8)-1); |
| 167 | |
| 168 | if (__msan_get_track_origins()) { |
| 169 | Origin o = Origin::CreateHeapOrigin(stack); |
| 170 | SetOrigin(dst, size, o.raw_id()); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | } // namespace __msan |