1 //===-- msan_poisoning.cpp --------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of MemorySanitizer.
11 //===----------------------------------------------------------------------===//
13 #include "msan_poisoning.h"
15 #include "interception/interception.h"
16 #include "msan_origin.h"
17 #include "msan_thread.h"
18 #include "sanitizer_common/sanitizer_common.h"
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
)
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);
33 void SetOriginIfPoisoned(uptr addr
, uptr src_shadow
, uptr size
,
35 uptr dst_s
= MEM_TO_SHADOW(addr
);
36 uptr src_s
= src_shadow
;
37 uptr src_s_end
= src_s
+ size
;
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
;
43 void CopyOrigin(const void *dst
, const void *src
, uptr size
,
45 if (!MEM_IS_APP(dst
) || !MEM_IS_APP(src
)) return;
49 // Copy left unaligned origin if that memory is poisoned.
51 u32 o
= GetOriginIfPoisoned((uptr
)src
, beg
+ 4 - d
);
53 if (__msan_get_track_origins() > 1) o
= ChainOrigin(o
, stack
);
54 *(u32
*)MEM_TO_ORIGIN(beg
) = o
;
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;
63 // Copy right unaligned origin if that memory is poisoned.
65 u32 o
= GetOriginIfPoisoned((uptr
)src
+ (end
- d
), (d
+ size
) - end
);
67 if (__msan_get_track_origins() > 1) o
= ChainOrigin(o
, stack
);
68 *(u32
*)MEM_TO_ORIGIN(end
) = o
;
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
);
83 for (; src
< src_end
; ++src
, ++src_s
, ++dst
) {
84 if (!*src_s
) continue;
87 dst_o
= ChainOrigin(src_o
, stack
);
92 REAL(memcpy
)((void *)MEM_TO_ORIGIN(beg
), (void *)MEM_TO_ORIGIN(s
),
98 void ReverseCopyOrigin(const void *dst
, const void *src
, uptr size
,
100 if (!MEM_IS_APP(dst
) || !MEM_IS_APP(src
))
104 uptr end
= (d
+ size
) & ~3UL;
106 // Copy right unaligned origin if that memory is poisoned.
107 if (end
< d
+ size
) {
108 u32 o
= GetOriginIfPoisoned((uptr
)src
+ (end
- d
), (d
+ size
) - end
);
110 if (__msan_get_track_origins() > 1)
111 o
= ChainOrigin(o
, stack
);
112 *(u32
*)MEM_TO_ORIGIN(end
) = o
;
120 uptr s
= ((uptr
)src
+ 3) & ~3UL;
121 if (__msan_get_track_origins() > 1) {
122 u32
*src
= (u32
*)MEM_TO_ORIGIN(s
+ end
- beg
- 4);
123 u32
*src_s
= (u32
*)MEM_TO_SHADOW(s
+ end
- beg
- 4);
124 u32
*src_begin
= (u32
*)MEM_TO_ORIGIN(s
);
125 u32
*dst
= (u32
*)MEM_TO_ORIGIN(end
- 4);
128 for (; src
>= src_begin
; --src
, --src_s
, --dst
) {
133 dst_o
= ChainOrigin(src_o
, stack
);
139 ((void *)MEM_TO_ORIGIN(beg
), (void *)MEM_TO_ORIGIN(s
), end
- beg
- 4);
143 // Copy left unaligned origin if that memory is poisoned.
145 u32 o
= GetOriginIfPoisoned((uptr
)src
, beg
+ 4 - d
);
147 if (__msan_get_track_origins() > 1)
148 o
= ChainOrigin(o
, stack
);
149 *(u32
*)MEM_TO_ORIGIN(beg
) = o
;
154 void MoveOrigin(const void *dst
, const void *src
, uptr size
,
156 // If destination origin range overlaps with source origin range, move
157 // origins by coping origins in a reverse order; otherwise, copy origins in
159 uptr src_aligned_beg
= reinterpret_cast<uptr
>(src
) & ~3UL;
160 uptr src_aligned_end
= (reinterpret_cast<uptr
>(src
) + size
) & ~3UL;
161 uptr dst_aligned_beg
= reinterpret_cast<uptr
>(dst
) & ~3UL;
162 if (dst_aligned_beg
< src_aligned_end
&& dst_aligned_beg
>= src_aligned_beg
)
163 return ReverseCopyOrigin(dst
, src
, size
, stack
);
164 return CopyOrigin(dst
, src
, size
, stack
);
167 void MoveShadowAndOrigin(const void *dst
, const void *src
, uptr size
,
169 if (!MEM_IS_APP(dst
)) return;
170 if (!MEM_IS_APP(src
)) return;
171 if (src
== dst
) return;
172 // MoveOrigin transfers origins by refering to their shadows. So we
173 // need to move origins before moving shadows.
174 if (__msan_get_track_origins())
175 MoveOrigin(dst
, src
, size
, stack
);
176 REAL(memmove
)((void *)MEM_TO_SHADOW((uptr
)dst
),
177 (void *)MEM_TO_SHADOW((uptr
)src
), size
);
180 void CopyShadowAndOrigin(const void *dst
, const void *src
, uptr size
,
182 if (!MEM_IS_APP(dst
)) return;
183 if (!MEM_IS_APP(src
)) return;
184 // Because origin's range is slightly larger than app range, memcpy may also
185 // cause overlapped origin ranges.
186 REAL(memcpy
)((void *)MEM_TO_SHADOW((uptr
)dst
),
187 (void *)MEM_TO_SHADOW((uptr
)src
), size
);
188 if (__msan_get_track_origins())
189 MoveOrigin(dst
, src
, size
, stack
);
192 void CopyMemory(void *dst
, const void *src
, uptr size
, StackTrace
*stack
) {
193 REAL(memcpy
)(dst
, src
, size
);
194 CopyShadowAndOrigin(dst
, src
, size
, stack
);
197 void SetShadow(const void *ptr
, uptr size
, u8 value
) {
198 uptr PageSize
= GetPageSizeCached();
199 uptr shadow_beg
= MEM_TO_SHADOW(ptr
);
200 uptr shadow_end
= shadow_beg
+ size
;
202 shadow_end
- shadow_beg
< common_flags()->clear_shadow_mmap_threshold
) {
203 REAL(memset
)((void *)shadow_beg
, value
, shadow_end
- shadow_beg
);
205 uptr page_beg
= RoundUpTo(shadow_beg
, PageSize
);
206 uptr page_end
= RoundDownTo(shadow_end
, PageSize
);
208 if (page_beg
>= page_end
) {
209 REAL(memset
)((void *)shadow_beg
, 0, shadow_end
- shadow_beg
);
211 if (page_beg
!= shadow_beg
) {
212 REAL(memset
)((void *)shadow_beg
, 0, page_beg
- shadow_beg
);
214 if (page_end
!= shadow_end
) {
215 REAL(memset
)((void *)page_end
, 0, shadow_end
- page_end
);
217 if (!MmapFixedSuperNoReserve(page_beg
, page_end
- page_beg
))
220 if (__msan_get_track_origins()) {
221 // No need to set origin for zero shadow, but we can release pages.
222 uptr origin_beg
= RoundUpTo(MEM_TO_ORIGIN(ptr
), PageSize
);
223 if (!MmapFixedSuperNoReserve(origin_beg
, page_end
- page_beg
))
230 void SetOrigin(const void *dst
, uptr size
, u32 origin
) {
231 // Origin mapping is 4 bytes per 4 bytes of application memory.
232 // Here we extend the range such that its left and right bounds are both
234 uptr x
= MEM_TO_ORIGIN((uptr
)dst
);
235 uptr beg
= x
& ~3UL; // align down.
236 uptr end
= (x
+ size
+ 3) & ~3UL; // align up.
237 u64 origin64
= ((u64
)origin
<< 32) | origin
;
238 // This is like memset, but the value is 32-bit. We unroll by 2 to write
239 // 64 bits at once. May want to unroll further to get 128-bit stores.
241 *(u32
*)beg
= origin
;
244 for (uptr addr
= beg
; addr
< (end
& ~7UL); addr
+= 8) *(u64
*)addr
= origin64
;
245 if (end
& 7ULL) *(u32
*)(end
- 4) = origin
;
248 void PoisonMemory(const void *dst
, uptr size
, StackTrace
*stack
) {
249 SetShadow(dst
, size
, (u8
)-1);
251 if (__msan_get_track_origins()) {
252 MsanThread
*t
= GetCurrentThread();
253 if (t
&& t
->InSignalHandler())
255 Origin o
= Origin::CreateHeapOrigin(stack
);
256 SetOrigin(dst
, size
, o
.raw_id());
260 } // namespace __msan