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
GetOriginIfPoisoned(uptr addr,uptr size)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
SetOriginIfPoisoned(uptr addr,uptr src_shadow,uptr size,u32 src_origin)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
CopyOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)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
MoveShadowAndOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)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
CopyShadowAndOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)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
CopyMemory(void * dst,const void * src,uptr size,StackTrace * stack)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
SetShadow(const void * ptr,uptr size,u8 value)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
SetOrigin(const void * dst,uptr size,u32 origin)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
PoisonMemory(const void * dst,uptr size,StackTrace * stack)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
175