13cab2bb3Spatrick //===-- msan_poisoning.cpp --------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of MemorySanitizer.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick 
133cab2bb3Spatrick #include "msan_poisoning.h"
143cab2bb3Spatrick 
153cab2bb3Spatrick #include "interception/interception.h"
163cab2bb3Spatrick #include "msan_origin.h"
17*810390e3Srobert #include "msan_thread.h"
183cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
193cab2bb3Spatrick 
203cab2bb3Spatrick DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
213cab2bb3Spatrick DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
223cab2bb3Spatrick DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n)
233cab2bb3Spatrick 
243cab2bb3Spatrick namespace __msan {
253cab2bb3Spatrick 
GetOriginIfPoisoned(uptr addr,uptr size)263cab2bb3Spatrick u32 GetOriginIfPoisoned(uptr addr, uptr size) {
273cab2bb3Spatrick   unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);
283cab2bb3Spatrick   for (uptr i = 0; i < size; ++i)
293cab2bb3Spatrick     if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);
303cab2bb3Spatrick   return 0;
313cab2bb3Spatrick }
323cab2bb3Spatrick 
SetOriginIfPoisoned(uptr addr,uptr src_shadow,uptr size,u32 src_origin)333cab2bb3Spatrick void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,
343cab2bb3Spatrick                          u32 src_origin) {
353cab2bb3Spatrick   uptr dst_s = MEM_TO_SHADOW(addr);
363cab2bb3Spatrick   uptr src_s = src_shadow;
373cab2bb3Spatrick   uptr src_s_end = src_s + size;
383cab2bb3Spatrick 
393cab2bb3Spatrick   for (; src_s < src_s_end; ++dst_s, ++src_s)
403cab2bb3Spatrick     if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin;
413cab2bb3Spatrick }
423cab2bb3Spatrick 
CopyOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)433cab2bb3Spatrick void CopyOrigin(const void *dst, const void *src, uptr size,
443cab2bb3Spatrick                 StackTrace *stack) {
453cab2bb3Spatrick   if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
463cab2bb3Spatrick 
473cab2bb3Spatrick   uptr d = (uptr)dst;
483cab2bb3Spatrick   uptr beg = d & ~3UL;
493cab2bb3Spatrick   // Copy left unaligned origin if that memory is poisoned.
503cab2bb3Spatrick   if (beg < d) {
51d89ec533Spatrick     u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d);
523cab2bb3Spatrick     if (o) {
533cab2bb3Spatrick       if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
543cab2bb3Spatrick       *(u32 *)MEM_TO_ORIGIN(beg) = o;
553cab2bb3Spatrick     }
563cab2bb3Spatrick     beg += 4;
573cab2bb3Spatrick   }
583cab2bb3Spatrick 
593cab2bb3Spatrick   uptr end = (d + size) & ~3UL;
603cab2bb3Spatrick   // If both ends fall into the same 4-byte slot, we are done.
613cab2bb3Spatrick   if (end < beg) return;
623cab2bb3Spatrick 
633cab2bb3Spatrick   // Copy right unaligned origin if that memory is poisoned.
643cab2bb3Spatrick   if (end < d + size) {
653cab2bb3Spatrick     u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
663cab2bb3Spatrick     if (o) {
673cab2bb3Spatrick       if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
683cab2bb3Spatrick       *(u32 *)MEM_TO_ORIGIN(end) = o;
693cab2bb3Spatrick     }
703cab2bb3Spatrick   }
713cab2bb3Spatrick 
723cab2bb3Spatrick   if (beg < end) {
733cab2bb3Spatrick     // Align src up.
743cab2bb3Spatrick     uptr s = ((uptr)src + 3) & ~3UL;
753cab2bb3Spatrick     // FIXME: factor out to msan_copy_origin_aligned
763cab2bb3Spatrick     if (__msan_get_track_origins() > 1) {
773cab2bb3Spatrick       u32 *src = (u32 *)MEM_TO_ORIGIN(s);
783cab2bb3Spatrick       u32 *src_s = (u32 *)MEM_TO_SHADOW(s);
793cab2bb3Spatrick       u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));
803cab2bb3Spatrick       u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);
813cab2bb3Spatrick       u32 src_o = 0;
823cab2bb3Spatrick       u32 dst_o = 0;
833cab2bb3Spatrick       for (; src < src_end; ++src, ++src_s, ++dst) {
843cab2bb3Spatrick         if (!*src_s) continue;
853cab2bb3Spatrick         if (*src != src_o) {
863cab2bb3Spatrick           src_o = *src;
873cab2bb3Spatrick           dst_o = ChainOrigin(src_o, stack);
883cab2bb3Spatrick         }
893cab2bb3Spatrick         *dst = dst_o;
903cab2bb3Spatrick       }
913cab2bb3Spatrick     } else {
923cab2bb3Spatrick       REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
933cab2bb3Spatrick                    end - beg);
943cab2bb3Spatrick     }
953cab2bb3Spatrick   }
963cab2bb3Spatrick }
973cab2bb3Spatrick 
ReverseCopyOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)98d89ec533Spatrick void ReverseCopyOrigin(const void *dst, const void *src, uptr size,
99d89ec533Spatrick                        StackTrace *stack) {
100d89ec533Spatrick   if (!MEM_IS_APP(dst) || !MEM_IS_APP(src))
101d89ec533Spatrick     return;
102d89ec533Spatrick 
103d89ec533Spatrick   uptr d = (uptr)dst;
104d89ec533Spatrick   uptr end = (d + size) & ~3UL;
105d89ec533Spatrick 
106d89ec533Spatrick   // Copy right unaligned origin if that memory is poisoned.
107d89ec533Spatrick   if (end < d + size) {
108d89ec533Spatrick     u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
109d89ec533Spatrick     if (o) {
110d89ec533Spatrick       if (__msan_get_track_origins() > 1)
111d89ec533Spatrick         o = ChainOrigin(o, stack);
112d89ec533Spatrick       *(u32 *)MEM_TO_ORIGIN(end) = o;
113d89ec533Spatrick     }
114d89ec533Spatrick   }
115d89ec533Spatrick 
116d89ec533Spatrick   uptr beg = d & ~3UL;
117d89ec533Spatrick 
118d89ec533Spatrick   if (beg + 4 < end) {
119d89ec533Spatrick     // Align src up.
120d89ec533Spatrick     uptr s = ((uptr)src + 3) & ~3UL;
121d89ec533Spatrick     if (__msan_get_track_origins() > 1) {
122d89ec533Spatrick       u32 *src = (u32 *)MEM_TO_ORIGIN(s + end - beg - 4);
123d89ec533Spatrick       u32 *src_s = (u32 *)MEM_TO_SHADOW(s + end - beg - 4);
124d89ec533Spatrick       u32 *src_begin = (u32 *)MEM_TO_ORIGIN(s);
125d89ec533Spatrick       u32 *dst = (u32 *)MEM_TO_ORIGIN(end - 4);
126d89ec533Spatrick       u32 src_o = 0;
127d89ec533Spatrick       u32 dst_o = 0;
128d89ec533Spatrick       for (; src >= src_begin; --src, --src_s, --dst) {
129d89ec533Spatrick         if (!*src_s)
130d89ec533Spatrick           continue;
131d89ec533Spatrick         if (*src != src_o) {
132d89ec533Spatrick           src_o = *src;
133d89ec533Spatrick           dst_o = ChainOrigin(src_o, stack);
134d89ec533Spatrick         }
135d89ec533Spatrick         *dst = dst_o;
136d89ec533Spatrick       }
137d89ec533Spatrick     } else {
138d89ec533Spatrick       REAL(memmove)
139d89ec533Spatrick       ((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), end - beg - 4);
140d89ec533Spatrick     }
141d89ec533Spatrick   }
142d89ec533Spatrick 
143d89ec533Spatrick   // Copy left unaligned origin if that memory is poisoned.
144d89ec533Spatrick   if (beg < d) {
145d89ec533Spatrick     u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d);
146d89ec533Spatrick     if (o) {
147d89ec533Spatrick       if (__msan_get_track_origins() > 1)
148d89ec533Spatrick         o = ChainOrigin(o, stack);
149d89ec533Spatrick       *(u32 *)MEM_TO_ORIGIN(beg) = o;
150d89ec533Spatrick     }
151d89ec533Spatrick   }
152d89ec533Spatrick }
153d89ec533Spatrick 
MoveOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)154d89ec533Spatrick void MoveOrigin(const void *dst, const void *src, uptr size,
155d89ec533Spatrick                 StackTrace *stack) {
156d89ec533Spatrick   // If destination origin range overlaps with source origin range, move
157d89ec533Spatrick   // origins by coping origins in a reverse order; otherwise, copy origins in
158d89ec533Spatrick   // a normal order.
159d89ec533Spatrick   uptr src_aligned_beg = reinterpret_cast<uptr>(src) & ~3UL;
160d89ec533Spatrick   uptr src_aligned_end = (reinterpret_cast<uptr>(src) + size) & ~3UL;
161d89ec533Spatrick   uptr dst_aligned_beg = reinterpret_cast<uptr>(dst) & ~3UL;
162d89ec533Spatrick   if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)
163d89ec533Spatrick     return ReverseCopyOrigin(dst, src, size, stack);
164d89ec533Spatrick   return CopyOrigin(dst, src, size, stack);
165d89ec533Spatrick }
166d89ec533Spatrick 
MoveShadowAndOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)1673cab2bb3Spatrick void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,
1683cab2bb3Spatrick                          StackTrace *stack) {
1693cab2bb3Spatrick   if (!MEM_IS_APP(dst)) return;
1703cab2bb3Spatrick   if (!MEM_IS_APP(src)) return;
1713cab2bb3Spatrick   if (src == dst) return;
172d89ec533Spatrick   // MoveOrigin transfers origins by refering to their shadows. So we
173d89ec533Spatrick   // need to move origins before moving shadows.
174d89ec533Spatrick   if (__msan_get_track_origins())
175d89ec533Spatrick     MoveOrigin(dst, src, size, stack);
1763cab2bb3Spatrick   REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
1773cab2bb3Spatrick                 (void *)MEM_TO_SHADOW((uptr)src), size);
1783cab2bb3Spatrick }
1793cab2bb3Spatrick 
CopyShadowAndOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)1803cab2bb3Spatrick void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
1813cab2bb3Spatrick                          StackTrace *stack) {
1823cab2bb3Spatrick   if (!MEM_IS_APP(dst)) return;
1833cab2bb3Spatrick   if (!MEM_IS_APP(src)) return;
184d89ec533Spatrick   // Because origin's range is slightly larger than app range, memcpy may also
185d89ec533Spatrick   // cause overlapped origin ranges.
1863cab2bb3Spatrick   REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
1873cab2bb3Spatrick                (void *)MEM_TO_SHADOW((uptr)src), size);
188d89ec533Spatrick   if (__msan_get_track_origins())
189d89ec533Spatrick     MoveOrigin(dst, src, size, stack);
1903cab2bb3Spatrick }
1913cab2bb3Spatrick 
CopyMemory(void * dst,const void * src,uptr size,StackTrace * stack)1923cab2bb3Spatrick void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {
1933cab2bb3Spatrick   REAL(memcpy)(dst, src, size);
1943cab2bb3Spatrick   CopyShadowAndOrigin(dst, src, size, stack);
1953cab2bb3Spatrick }
1963cab2bb3Spatrick 
SetShadow(const void * ptr,uptr size,u8 value)1973cab2bb3Spatrick void SetShadow(const void *ptr, uptr size, u8 value) {
1983cab2bb3Spatrick   uptr PageSize = GetPageSizeCached();
1993cab2bb3Spatrick   uptr shadow_beg = MEM_TO_SHADOW(ptr);
2003cab2bb3Spatrick   uptr shadow_end = shadow_beg + size;
2013cab2bb3Spatrick   if (value ||
2023cab2bb3Spatrick       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
2033cab2bb3Spatrick     REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg);
2043cab2bb3Spatrick   } else {
2053cab2bb3Spatrick     uptr page_beg = RoundUpTo(shadow_beg, PageSize);
2063cab2bb3Spatrick     uptr page_end = RoundDownTo(shadow_end, PageSize);
2073cab2bb3Spatrick 
2083cab2bb3Spatrick     if (page_beg >= page_end) {
2093cab2bb3Spatrick       REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
2103cab2bb3Spatrick     } else {
2113cab2bb3Spatrick       if (page_beg != shadow_beg) {
2123cab2bb3Spatrick         REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
2133cab2bb3Spatrick       }
2143cab2bb3Spatrick       if (page_end != shadow_end) {
2153cab2bb3Spatrick         REAL(memset)((void *)page_end, 0, shadow_end - page_end);
2163cab2bb3Spatrick       }
217d89ec533Spatrick       if (!MmapFixedSuperNoReserve(page_beg, page_end - page_beg))
2183cab2bb3Spatrick         Die();
2193cab2bb3Spatrick     }
2203cab2bb3Spatrick   }
2213cab2bb3Spatrick }
2223cab2bb3Spatrick 
SetOrigin(const void * dst,uptr size,u32 origin)2233cab2bb3Spatrick void SetOrigin(const void *dst, uptr size, u32 origin) {
2243cab2bb3Spatrick   // Origin mapping is 4 bytes per 4 bytes of application memory.
2253cab2bb3Spatrick   // Here we extend the range such that its left and right bounds are both
2263cab2bb3Spatrick   // 4 byte aligned.
2273cab2bb3Spatrick   uptr x = MEM_TO_ORIGIN((uptr)dst);
2283cab2bb3Spatrick   uptr beg = x & ~3UL;               // align down.
2293cab2bb3Spatrick   uptr end = (x + size + 3) & ~3UL;  // align up.
2303cab2bb3Spatrick   u64 origin64 = ((u64)origin << 32) | origin;
2313cab2bb3Spatrick   // This is like memset, but the value is 32-bit. We unroll by 2 to write
2323cab2bb3Spatrick   // 64 bits at once. May want to unroll further to get 128-bit stores.
2333cab2bb3Spatrick   if (beg & 7ULL) {
2343cab2bb3Spatrick     *(u32 *)beg = origin;
2353cab2bb3Spatrick     beg += 4;
2363cab2bb3Spatrick   }
2373cab2bb3Spatrick   for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64;
2383cab2bb3Spatrick   if (end & 7ULL) *(u32 *)(end - 4) = origin;
2393cab2bb3Spatrick }
2403cab2bb3Spatrick 
PoisonMemory(const void * dst,uptr size,StackTrace * stack)2413cab2bb3Spatrick void PoisonMemory(const void *dst, uptr size, StackTrace *stack) {
2423cab2bb3Spatrick   SetShadow(dst, size, (u8)-1);
2433cab2bb3Spatrick 
2443cab2bb3Spatrick   if (__msan_get_track_origins()) {
245*810390e3Srobert     MsanThread *t = GetCurrentThread();
246*810390e3Srobert     if (t && t->InSignalHandler())
247*810390e3Srobert       return;
2483cab2bb3Spatrick     Origin o = Origin::CreateHeapOrigin(stack);
2493cab2bb3Spatrick     SetOrigin(dst, size, o.raw_id());
2503cab2bb3Spatrick   }
2513cab2bb3Spatrick }
2523cab2bb3Spatrick 
2533cab2bb3Spatrick }  // namespace __msan
254