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