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