1 1.1 kamil //===-- asan_poisoning.h ----------------------------------------*- C++ -*-===// 2 1.1 kamil // 3 1.1 kamil // The LLVM Compiler Infrastructure 4 1.1 kamil // 5 1.1 kamil // This file is distributed under the University of Illinois Open Source 6 1.1 kamil // License. See LICENSE.TXT for details. 7 1.1 kamil // 8 1.1 kamil //===----------------------------------------------------------------------===// 9 1.1 kamil // 10 1.1 kamil // This file is a part of AddressSanitizer, an address sanity checker. 11 1.1 kamil // 12 1.1 kamil // Shadow memory poisoning by ASan RTL and by user application. 13 1.1 kamil //===----------------------------------------------------------------------===// 14 1.1 kamil 15 1.1 kamil #include "asan_interceptors.h" 16 1.1 kamil #include "asan_internal.h" 17 1.1 kamil #include "asan_mapping.h" 18 1.1 kamil #include "sanitizer_common/sanitizer_flags.h" 19 1.1 kamil 20 1.1 kamil namespace __asan { 21 1.1 kamil 22 1.1 kamil // Enable/disable memory poisoning. 23 1.1 kamil void SetCanPoisonMemory(bool value); 24 1.1 kamil bool CanPoisonMemory(); 25 1.1 kamil 26 1.1 kamil // Poisons the shadow memory for "size" bytes starting from "addr". 27 1.1 kamil void PoisonShadow(uptr addr, uptr size, u8 value); 28 1.1 kamil 29 1.1 kamil // Poisons the shadow memory for "redzone_size" bytes starting from 30 1.1 kamil // "addr + size". 31 1.1 kamil void PoisonShadowPartialRightRedzone(uptr addr, 32 1.1 kamil uptr size, 33 1.1 kamil uptr redzone_size, 34 1.1 kamil u8 value); 35 1.1 kamil 36 1.1 kamil // Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that 37 1.1 kamil // assume that memory addresses are properly aligned. Use in 38 1.1 kamil // performance-critical code with care. 39 1.1 kamil ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, 40 1.1 kamil u8 value) { 41 1.1 kamil DCHECK(!value || CanPoisonMemory()); 42 1.1 kamil uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); 43 1.1 kamil uptr shadow_end = MEM_TO_SHADOW( 44 1.1 kamil aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; 45 1.1 kamil // FIXME: Page states are different on Windows, so using the same interface 46 1.1 kamil // for mapping shadow and zeroing out pages doesn't "just work", so we should 47 1.1 kamil // probably provide higher-level interface for these operations. 48 1.1 kamil // For now, just memset on Windows. 49 1.1 kamil if (value || SANITIZER_WINDOWS == 1 || 50 1.1 kamil // TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be 51 1.1 kamil // changed at all. It doesn't currently have an efficient means 52 1.1 kamil // to zero a bunch of pages, but maybe we should add one. 53 1.1 kamil SANITIZER_FUCHSIA == 1 || 54 1.1 kamil // RTEMS doesn't have have pages, let alone a fast way to zero 55 1.1 kamil // them, so default to memset. 56 1.1 kamil SANITIZER_RTEMS == 1 || 57 1.1 kamil shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { 58 1.1 kamil REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); 59 1.1 kamil } else { 60 1.1 kamil uptr page_size = GetPageSizeCached(); 61 1.1 kamil uptr page_beg = RoundUpTo(shadow_beg, page_size); 62 1.1 kamil uptr page_end = RoundDownTo(shadow_end, page_size); 63 1.1 kamil 64 1.1 kamil if (page_beg >= page_end) { 65 1.1 kamil REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); 66 1.1 kamil } else { 67 1.1 kamil if (page_beg != shadow_beg) { 68 1.1 kamil REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg); 69 1.1 kamil } 70 1.1 kamil if (page_end != shadow_end) { 71 1.1 kamil REAL(memset)((void *)page_end, 0, shadow_end - page_end); 72 1.1 kamil } 73 1.1 kamil ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); 74 1.1 kamil } 75 1.1 kamil } 76 1.1 kamil } 77 1.1 kamil 78 1.1 kamil ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( 79 1.1 kamil uptr aligned_addr, uptr size, uptr redzone_size, u8 value) { 80 1.1 kamil DCHECK(CanPoisonMemory()); 81 1.1 kamil bool poison_partial = flags()->poison_partial; 82 1.1 kamil u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr); 83 1.1 kamil for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) { 84 1.1 kamil if (i + SHADOW_GRANULARITY <= size) { 85 1.1 kamil *shadow = 0; // fully addressable 86 1.1 kamil } else if (i >= size) { 87 1.1 kamil *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable 88 1.1 kamil } else { 89 1.1 kamil // first size-i bytes are addressable 90 1.1 kamil *shadow = poison_partial ? static_cast<u8>(size - i) : 0; 91 1.1 kamil } 92 1.1 kamil } 93 1.1 kamil } 94 1.1 kamil 95 1.1 kamil // Calls __sanitizer::ReleaseMemoryPagesToOS() on 96 1.1 kamil // [MemToShadow(p), MemToShadow(p+size)]. 97 1.1 kamil void FlushUnneededASanShadowMemory(uptr p, uptr size); 98 1.1 kamil 99 1.1 kamil } // namespace __asan 100