Path: blob/main/contrib/llvm-project/compiler-rt/lib/msan/msan_poisoning.cpp
35262 views
//===-- msan_poisoning.cpp --------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of MemorySanitizer.9//10//===----------------------------------------------------------------------===//1112#include "msan_poisoning.h"1314#include "interception/interception.h"15#include "msan_origin.h"16#include "msan_thread.h"17#include "sanitizer_common/sanitizer_common.h"1819DECLARE_REAL(void *, memset, void *dest, int c, uptr n)20DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)21DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n)2223namespace __msan {2425u32 GetOriginIfPoisoned(uptr addr, uptr size) {26unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);27for (uptr i = 0; i < size; ++i)28if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);29return 0;30}3132void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,33u32 src_origin) {34uptr dst_s = MEM_TO_SHADOW(addr);35uptr src_s = src_shadow;36uptr src_s_end = src_s + size;3738for (; src_s < src_s_end; ++dst_s, ++src_s)39if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin;40}4142void CopyOrigin(const void *dst, const void *src, uptr size,43StackTrace *stack) {44if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;4546uptr d = (uptr)dst;47uptr beg = d & ~3UL;48// Copy left unaligned origin if that memory is poisoned.49if (beg < d) {50u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d);51if (o) {52if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);53*(u32 *)MEM_TO_ORIGIN(beg) = o;54}55beg += 4;56}5758uptr end = (d + size) & ~3UL;59// If both ends fall into the same 4-byte slot, we are done.60if (end < beg) return;6162// Copy right unaligned origin if that memory is poisoned.63if (end < d + size) {64u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);65if (o) {66if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);67*(u32 *)MEM_TO_ORIGIN(end) = o;68}69}7071if (beg < end) {72// Align src up.73uptr s = ((uptr)src + 3) & ~3UL;74// FIXME: factor out to msan_copy_origin_aligned75if (__msan_get_track_origins() > 1) {76u32 *src = (u32 *)MEM_TO_ORIGIN(s);77u32 *src_s = (u32 *)MEM_TO_SHADOW(s);78u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));79u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);80u32 src_o = 0;81u32 dst_o = 0;82for (; src < src_end; ++src, ++src_s, ++dst) {83if (!*src_s) continue;84if (*src != src_o) {85src_o = *src;86dst_o = ChainOrigin(src_o, stack);87}88*dst = dst_o;89}90} else {91REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),92end - beg);93}94}95}9697void ReverseCopyOrigin(const void *dst, const void *src, uptr size,98StackTrace *stack) {99if (!MEM_IS_APP(dst) || !MEM_IS_APP(src))100return;101102uptr d = (uptr)dst;103uptr end = (d + size) & ~3UL;104105// Copy right unaligned origin if that memory is poisoned.106if (end < d + size) {107u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);108if (o) {109if (__msan_get_track_origins() > 1)110o = ChainOrigin(o, stack);111*(u32 *)MEM_TO_ORIGIN(end) = o;112}113}114115uptr beg = d & ~3UL;116117if (beg + 4 < end) {118// Align src up.119uptr s = ((uptr)src + 3) & ~3UL;120if (__msan_get_track_origins() > 1) {121u32 *src = (u32 *)MEM_TO_ORIGIN(s + end - beg - 4);122u32 *src_s = (u32 *)MEM_TO_SHADOW(s + end - beg - 4);123u32 *src_begin = (u32 *)MEM_TO_ORIGIN(s);124u32 *dst = (u32 *)MEM_TO_ORIGIN(end - 4);125u32 src_o = 0;126u32 dst_o = 0;127for (; src >= src_begin; --src, --src_s, --dst) {128if (!*src_s)129continue;130if (*src != src_o) {131src_o = *src;132dst_o = ChainOrigin(src_o, stack);133}134*dst = dst_o;135}136} else {137REAL(memmove)138((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s), end - beg - 4);139}140}141142// Copy left unaligned origin if that memory is poisoned.143if (beg < d) {144u32 o = GetOriginIfPoisoned((uptr)src, beg + 4 - d);145if (o) {146if (__msan_get_track_origins() > 1)147o = ChainOrigin(o, stack);148*(u32 *)MEM_TO_ORIGIN(beg) = o;149}150}151}152153void MoveOrigin(const void *dst, const void *src, uptr size,154StackTrace *stack) {155// If destination origin range overlaps with source origin range, move156// origins by coping origins in a reverse order; otherwise, copy origins in157// a normal order.158uptr src_aligned_beg = reinterpret_cast<uptr>(src) & ~3UL;159uptr src_aligned_end = (reinterpret_cast<uptr>(src) + size) & ~3UL;160uptr dst_aligned_beg = reinterpret_cast<uptr>(dst) & ~3UL;161if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)162return ReverseCopyOrigin(dst, src, size, stack);163return CopyOrigin(dst, src, size, stack);164}165166void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,167StackTrace *stack) {168if (!MEM_IS_APP(dst)) return;169if (!MEM_IS_APP(src)) return;170if (src == dst) return;171// MoveOrigin transfers origins by refering to their shadows. So we172// need to move origins before moving shadows.173if (__msan_get_track_origins())174MoveOrigin(dst, src, size, stack);175REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),176(void *)MEM_TO_SHADOW((uptr)src), size);177}178179void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,180StackTrace *stack) {181if (!MEM_IS_APP(dst)) return;182if (!MEM_IS_APP(src)) return;183// Because origin's range is slightly larger than app range, memcpy may also184// cause overlapped origin ranges.185REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),186(void *)MEM_TO_SHADOW((uptr)src), size);187if (__msan_get_track_origins())188MoveOrigin(dst, src, size, stack);189}190191void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {192REAL(memcpy)(dst, src, size);193CopyShadowAndOrigin(dst, src, size, stack);194}195196void SetShadow(const void *ptr, uptr size, u8 value) {197uptr PageSize = GetPageSizeCached();198uptr shadow_beg = MEM_TO_SHADOW(ptr);199uptr shadow_end = shadow_beg + size;200if (value ||201shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {202REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg);203} else {204uptr page_beg = RoundUpTo(shadow_beg, PageSize);205uptr page_end = RoundDownTo(shadow_end, PageSize);206207if (page_beg >= page_end) {208REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);209} else {210if (page_beg != shadow_beg) {211REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);212}213if (page_end != shadow_end) {214REAL(memset)((void *)page_end, 0, shadow_end - page_end);215}216if (!MmapFixedSuperNoReserve(page_beg, page_end - page_beg))217Die();218219if (__msan_get_track_origins()) {220// No need to set origin for zero shadow, but we can release pages.221uptr origin_beg = RoundUpTo(MEM_TO_ORIGIN(ptr), PageSize);222if (!MmapFixedSuperNoReserve(origin_beg, page_end - page_beg))223Die();224}225}226}227}228229void SetOrigin(const void *dst, uptr size, u32 origin) {230// Origin mapping is 4 bytes per 4 bytes of application memory.231// Here we extend the range such that its left and right bounds are both232// 4 byte aligned.233uptr x = MEM_TO_ORIGIN((uptr)dst);234uptr beg = x & ~3UL; // align down.235uptr end = (x + size + 3) & ~3UL; // align up.236u64 origin64 = ((u64)origin << 32) | origin;237// This is like memset, but the value is 32-bit. We unroll by 2 to write238// 64 bits at once. May want to unroll further to get 128-bit stores.239if (beg & 7ULL) {240*(u32 *)beg = origin;241beg += 4;242}243for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64;244if (end & 7ULL) *(u32 *)(end - 4) = origin;245}246247void PoisonMemory(const void *dst, uptr size, StackTrace *stack) {248SetShadow(dst, size, (u8)-1);249250if (__msan_get_track_origins()) {251MsanThread *t = GetCurrentThread();252if (t && t->InSignalHandler())253return;254Origin o = Origin::CreateHeapOrigin(stack);255SetOrigin(dst, size, o.raw_id());256}257}258259} // namespace __msan260261262