1251034Sed//===-- asan_poisoning.h ----------------------------------------*- C++ -*-===// 2251034Sed// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6251034Sed// 7251034Sed//===----------------------------------------------------------------------===// 8251034Sed// 9251034Sed// This file is a part of AddressSanitizer, an address sanity checker. 10251034Sed// 11251034Sed// Shadow memory poisoning by ASan RTL and by user application. 12251034Sed//===----------------------------------------------------------------------===// 13251034Sed 14251034Sed#include "asan_interceptors.h" 15251034Sed#include "asan_internal.h" 16251034Sed#include "asan_mapping.h" 17276789Sdim#include "sanitizer_common/sanitizer_flags.h" 18353358Sdim#include "sanitizer_common/sanitizer_platform.h" 19251034Sed 20251034Sednamespace __asan { 21251034Sed 22280031Sdim// Enable/disable memory poisoning. 23280031Sdimvoid SetCanPoisonMemory(bool value); 24280031Sdimbool CanPoisonMemory(); 25280031Sdim 26251034Sed// Poisons the shadow memory for "size" bytes starting from "addr". 27251034Sedvoid PoisonShadow(uptr addr, uptr size, u8 value); 28251034Sed 29251034Sed// Poisons the shadow memory for "redzone_size" bytes starting from 30251034Sed// "addr + size". 31251034Sedvoid PoisonShadowPartialRightRedzone(uptr addr, 32251034Sed uptr size, 33251034Sed uptr redzone_size, 34251034Sed u8 value); 35251034Sed 36251034Sed// Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that 37251034Sed// assume that memory addresses are properly aligned. Use in 38251034Sed// performance-critical code with care. 39251034SedALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, 40251034Sed u8 value) { 41341825Sdim DCHECK(!value || CanPoisonMemory()); 42353358Sdim#if SANITIZER_FUCHSIA 43353358Sdim __sanitizer_fill_shadow(aligned_beg, aligned_size, value, 44353358Sdim common_flags()->clear_shadow_mmap_threshold); 45353358Sdim#else 46251034Sed uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); 47251034Sed uptr shadow_end = MEM_TO_SHADOW( 48251034Sed aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; 49276789Sdim // FIXME: Page states are different on Windows, so using the same interface 50276789Sdim // for mapping shadow and zeroing out pages doesn't "just work", so we should 51276789Sdim // probably provide higher-level interface for these operations. 52276789Sdim // For now, just memset on Windows. 53327952Sdim if (value || SANITIZER_WINDOWS == 1 || 54341825Sdim // RTEMS doesn't have have pages, let alone a fast way to zero 55341825Sdim // them, so default to memset. 56341825Sdim SANITIZER_RTEMS == 1 || 57276789Sdim shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { 58276789Sdim REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); 59276789Sdim } else { 60276789Sdim uptr page_size = GetPageSizeCached(); 61276789Sdim uptr page_beg = RoundUpTo(shadow_beg, page_size); 62276789Sdim uptr page_end = RoundDownTo(shadow_end, page_size); 63276789Sdim 64276789Sdim if (page_beg >= page_end) { 65276789Sdim REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); 66276789Sdim } else { 67276789Sdim if (page_beg != shadow_beg) { 68276789Sdim REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); 69276789Sdim } 70276789Sdim if (page_end != shadow_end) { 71276789Sdim REAL(memset)((void *)page_end, 0, shadow_end - page_end); 72276789Sdim } 73288943Sdim ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); 74276789Sdim } 75276789Sdim } 76353358Sdim#endif // SANITIZER_FUCHSIA 77251034Sed} 78251034Sed 79251034SedALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( 80251034Sed uptr aligned_addr, uptr size, uptr redzone_size, u8 value) { 81280031Sdim DCHECK(CanPoisonMemory()); 82274201Sdim bool poison_partial = flags()->poison_partial; 83251034Sed u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr); 84251034Sed for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) { 85251034Sed if (i + SHADOW_GRANULARITY <= size) { 86251034Sed *shadow = 0; // fully addressable 87251034Sed } else if (i >= size) { 88251034Sed *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable 89251034Sed } else { 90274201Sdim // first size-i bytes are addressable 91274201Sdim *shadow = poison_partial ? static_cast<u8>(size - i) : 0; 92251034Sed } 93251034Sed } 94251034Sed} 95251034Sed 96314564Sdim// Calls __sanitizer::ReleaseMemoryPagesToOS() on 97314564Sdim// [MemToShadow(p), MemToShadow(p+size)]. 98276789Sdimvoid FlushUnneededASanShadowMemory(uptr p, uptr size); 99276789Sdim 100251034Sed} // namespace __asan 101