1353944Sdim//===-- msan_poisoning.cpp --------------------------------------*- C++ -*-===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is a part of MemorySanitizer. 10353944Sdim// 11353944Sdim//===----------------------------------------------------------------------===// 12353944Sdim 13353944Sdim#include "msan_poisoning.h" 14353944Sdim 15353944Sdim#include "interception/interception.h" 16353944Sdim#include "msan_origin.h" 17353944Sdim#include "sanitizer_common/sanitizer_common.h" 18353944Sdim 19353944SdimDECLARE_REAL(void *, memset, void *dest, int c, uptr n) 20353944SdimDECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) 21353944SdimDECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n) 22353944Sdim 23353944Sdimnamespace __msan { 24353944Sdim 25353944Sdimu32 GetOriginIfPoisoned(uptr addr, uptr size) { 26353944Sdim unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr); 27353944Sdim for (uptr i = 0; i < size; ++i) 28353944Sdim if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL); 29353944Sdim return 0; 30353944Sdim} 31353944Sdim 32353944Sdimvoid SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size, 33353944Sdim u32 src_origin) { 34353944Sdim uptr dst_s = MEM_TO_SHADOW(addr); 35353944Sdim uptr src_s = src_shadow; 36353944Sdim uptr src_s_end = src_s + size; 37353944Sdim 38353944Sdim for (; src_s < src_s_end; ++dst_s, ++src_s) 39353944Sdim if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin; 40353944Sdim} 41353944Sdim 42353944Sdimvoid CopyOrigin(const void *dst, const void *src, uptr size, 43353944Sdim StackTrace *stack) { 44353944Sdim if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return; 45353944Sdim 46353944Sdim uptr d = (uptr)dst; 47353944Sdim uptr beg = d & ~3UL; 48353944Sdim // Copy left unaligned origin if that memory is poisoned. 49353944Sdim if (beg < d) { 50353944Sdim u32 o = GetOriginIfPoisoned((uptr)src, d - beg); 51353944Sdim if (o) { 52353944Sdim if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); 53353944Sdim *(u32 *)MEM_TO_ORIGIN(beg) = o; 54353944Sdim } 55353944Sdim beg += 4; 56353944Sdim } 57353944Sdim 58353944Sdim uptr end = (d + size) & ~3UL; 59353944Sdim // If both ends fall into the same 4-byte slot, we are done. 60353944Sdim if (end < beg) return; 61353944Sdim 62353944Sdim // Copy right unaligned origin if that memory is poisoned. 63353944Sdim if (end < d + size) { 64353944Sdim u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end); 65353944Sdim if (o) { 66353944Sdim if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack); 67353944Sdim *(u32 *)MEM_TO_ORIGIN(end) = o; 68353944Sdim } 69353944Sdim } 70353944Sdim 71353944Sdim if (beg < end) { 72353944Sdim // Align src up. 73353944Sdim uptr s = ((uptr)src + 3) & ~3UL; 74353944Sdim // FIXME: factor out to msan_copy_origin_aligned 75353944Sdim if (__msan_get_track_origins() > 1) { 76353944Sdim u32 *src = (u32 *)MEM_TO_ORIGIN(s); 77353944Sdim u32 *src_s = (u32 *)MEM_TO_SHADOW(s); 78353944Sdim u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg)); 79353944Sdim u32 *dst = (u32 *)MEM_TO_ORIGIN(beg); 80353944Sdim u32 src_o = 0; 81353944Sdim u32 dst_o = 0; 82353944Sdim for (; src < src_end; ++src, ++src_s, ++dst) { 83353944Sdim if (!*src_s) continue; 84353944Sdim if (*src != src_o) { 85353944Sdim src_o = *src; 86353944Sdim dst_o = ChainOrigin(src_o, stack); 87353944Sdim } 88353944Sdim *dst = dst_o; 89353944Sdim } 90353944Sdim } else { 91353944Sdim REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), 92353944Sdim end - beg); 93353944Sdim } 94353944Sdim } 95353944Sdim} 96353944Sdim 97353944Sdimvoid MoveShadowAndOrigin(const void *dst, const void *src, uptr size, 98353944Sdim StackTrace *stack) { 99353944Sdim if (!MEM_IS_APP(dst)) return; 100353944Sdim if (!MEM_IS_APP(src)) return; 101353944Sdim if (src == dst) return; 102353944Sdim REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst), 103353944Sdim (void *)MEM_TO_SHADOW((uptr)src), size); 104353944Sdim if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack); 105353944Sdim} 106353944Sdim 107353944Sdimvoid CopyShadowAndOrigin(const void *dst, const void *src, uptr size, 108353944Sdim StackTrace *stack) { 109353944Sdim if (!MEM_IS_APP(dst)) return; 110353944Sdim if (!MEM_IS_APP(src)) return; 111353944Sdim REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst), 112353944Sdim (void *)MEM_TO_SHADOW((uptr)src), size); 113353944Sdim if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack); 114353944Sdim} 115353944Sdim 116353944Sdimvoid CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) { 117353944Sdim REAL(memcpy)(dst, src, size); 118353944Sdim CopyShadowAndOrigin(dst, src, size, stack); 119353944Sdim} 120353944Sdim 121353944Sdimvoid SetShadow(const void *ptr, uptr size, u8 value) { 122353944Sdim uptr PageSize = GetPageSizeCached(); 123353944Sdim uptr shadow_beg = MEM_TO_SHADOW(ptr); 124353944Sdim uptr shadow_end = shadow_beg + size; 125353944Sdim if (value || 126353944Sdim shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { 127353944Sdim REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg); 128353944Sdim } else { 129353944Sdim uptr page_beg = RoundUpTo(shadow_beg, PageSize); 130353944Sdim uptr page_end = RoundDownTo(shadow_end, PageSize); 131353944Sdim 132353944Sdim if (page_beg >= page_end) { 133353944Sdim REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); 134353944Sdim } else { 135353944Sdim if (page_beg != shadow_beg) { 136353944Sdim REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); 137353944Sdim } 138353944Sdim if (page_end != shadow_end) { 139353944Sdim REAL(memset)((void *)page_end, 0, shadow_end - page_end); 140353944Sdim } 141353944Sdim if (!MmapFixedNoReserve(page_beg, page_end - page_beg)) 142353944Sdim Die(); 143353944Sdim } 144353944Sdim } 145353944Sdim} 146353944Sdim 147353944Sdimvoid SetOrigin(const void *dst, uptr size, u32 origin) { 148353944Sdim // Origin mapping is 4 bytes per 4 bytes of application memory. 149353944Sdim // Here we extend the range such that its left and right bounds are both 150353944Sdim // 4 byte aligned. 151353944Sdim uptr x = MEM_TO_ORIGIN((uptr)dst); 152353944Sdim uptr beg = x & ~3UL; // align down. 153353944Sdim uptr end = (x + size + 3) & ~3UL; // align up. 154353944Sdim u64 origin64 = ((u64)origin << 32) | origin; 155353944Sdim // This is like memset, but the value is 32-bit. We unroll by 2 to write 156353944Sdim // 64 bits at once. May want to unroll further to get 128-bit stores. 157353944Sdim if (beg & 7ULL) { 158353944Sdim *(u32 *)beg = origin; 159353944Sdim beg += 4; 160353944Sdim } 161353944Sdim for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64; 162353944Sdim if (end & 7ULL) *(u32 *)(end - 4) = origin; 163353944Sdim} 164353944Sdim 165353944Sdimvoid PoisonMemory(const void *dst, uptr size, StackTrace *stack) { 166353944Sdim SetShadow(dst, size, (u8)-1); 167353944Sdim 168353944Sdim if (__msan_get_track_origins()) { 169353944Sdim Origin o = Origin::CreateHeapOrigin(stack); 170353944Sdim SetOrigin(dst, size, o.raw_id()); 171353944Sdim } 172353944Sdim} 173353944Sdim 174353944Sdim} // namespace __msan 175