asan_poisoning.h revision 1.1.1.8
1198090Srdivacky//===-- asan_poisoning.h ----------------------------------------*- C++ -*-===// 2198090Srdivacky// 3198090Srdivacky// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4198090Srdivacky// See https://llvm.org/LICENSE.txt for license information. 5198090Srdivacky// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6198090Srdivacky// 7198090Srdivacky//===----------------------------------------------------------------------===// 8198090Srdivacky// 9198090Srdivacky// This file is a part of AddressSanitizer, an address sanity checker. 10198090Srdivacky// 11198090Srdivacky// Shadow memory poisoning by ASan RTL and by user application. 12198090Srdivacky//===----------------------------------------------------------------------===// 13198090Srdivacky 14198090Srdivacky#include "asan_interceptors.h" 15198090Srdivacky#include "asan_internal.h" 16198090Srdivacky#include "asan_mapping.h" 17234353Sdim#include "sanitizer_common/sanitizer_flags.h" 18249423Sdim#include "sanitizer_common/sanitizer_platform.h" 19234353Sdim 20198090Srdivackynamespace __asan { 21198090Srdivacky 22234353Sdim// Enable/disable memory poisoning. 23234353Sdimvoid SetCanPoisonMemory(bool value); 24208599Srdivackybool CanPoisonMemory(); 25208599Srdivacky 26234353Sdim// Poisons the shadow memory for "size" bytes starting from "addr". 27234353Sdimvoid PoisonShadow(uptr addr, uptr size, u8 value); 28234353Sdim 29234353Sdim// Poisons the shadow memory for "redzone_size" bytes starting from 30198396Srdivacky// "addr + size". 31263508Sdimvoid PoisonShadowPartialRightRedzone(uptr addr, 32263508Sdim uptr size, 33263508Sdim uptr redzone_size, 34263508Sdim u8 value); 35198090Srdivacky 36198090Srdivacky// Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that 37198090Srdivacky// assume that memory addresses are properly aligned. Use in 38208599Srdivacky// performance-critical code with care. 39207618SrdivackyALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, 40207618Srdivacky u8 value) { 41263508Sdim DCHECK(!value || CanPoisonMemory()); 42263508Sdim#if SANITIZER_FUCHSIA 43207618Srdivacky __sanitizer_fill_shadow(aligned_beg, aligned_size, value, 44198090Srdivacky common_flags()->clear_shadow_mmap_threshold); 45198396Srdivacky#else 46212904Sdim uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); 47226633Sdim uptr shadow_end = MEM_TO_SHADOW( 48198396Srdivacky aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; 49263508Sdim // FIXME: Page states are different on Windows, so using the same interface 50212904Sdim // for mapping shadow and zeroing out pages doesn't "just work", so we should 51212904Sdim // probably provide higher-level interface for these operations. 52263508Sdim // For now, just memset on Windows. 53263508Sdim if (value || SANITIZER_WINDOWS == 1 || 54198090Srdivacky // RTEMS doesn't have have pages, let alone a fast way to zero 55208599Srdivacky // them, so default to memset. 56198090Srdivacky SANITIZER_RTEMS == 1 || 57263508Sdim shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { 58198090Srdivacky REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); 59198892Srdivacky } else { 60198090Srdivacky uptr page_size = GetPageSizeCached(); 61198396Srdivacky uptr page_beg = RoundUpTo(shadow_beg, page_size); 62263508Sdim uptr page_end = RoundDownTo(shadow_end, page_size); 63263508Sdim 64263508Sdim if (page_beg >= page_end) { 65263508Sdim REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); 66226633Sdim } else { 67198396Srdivacky if (page_beg != shadow_beg) { 68263508Sdim REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); 69263508Sdim } 70198090Srdivacky if (page_end != shadow_end) { 71198090Srdivacky REAL(memset)((void *)page_end, 0, shadow_end - page_end); 72263508Sdim } 73263508Sdim ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); 74198090Srdivacky } 75198396Srdivacky } 76263508Sdim#endif // SANITIZER_FUCHSIA 77263508Sdim} 78198090Srdivacky 79198396SrdivackyALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( 80263508Sdim uptr aligned_addr, uptr size, uptr redzone_size, u8 value) { 81263508Sdim DCHECK(CanPoisonMemory()); 82198090Srdivacky bool poison_partial = flags()->poison_partial; 83263508Sdim u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr); 84263508Sdim for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) { 85263508Sdim if (i + SHADOW_GRANULARITY <= size) { 86198090Srdivacky *shadow = 0; // fully addressable 87263508Sdim } else if (i >= size) { 88198090Srdivacky *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable 89198090Srdivacky } else { 90198090Srdivacky // first size-i bytes are addressable 91198090Srdivacky *shadow = poison_partial ? static_cast<u8>(size - i) : 0; 92198090Srdivacky } 93263508Sdim } 94198090Srdivacky} 95198090Srdivacky 96198090Srdivacky// Calls __sanitizer::ReleaseMemoryPagesToOS() on 97198090Srdivacky// [MemToShadow(p), MemToShadow(p+size)]. 98198090Srdivackyvoid FlushUnneededASanShadowMemory(uptr p, uptr size); 99198090Srdivacky 100198090Srdivacky} // namespace __asan 101198396Srdivacky