xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_poisoning.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- asan_poisoning.h ----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of AddressSanitizer, an address sanity checker.
10 //
11 // Shadow memory poisoning by ASan RTL and by user application.
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef ASAN_POISONING_H
15 #define ASAN_POISONING_H
16 
17 #include "asan_interceptors.h"
18 #include "asan_internal.h"
19 #include "asan_mapping.h"
20 #include "sanitizer_common/sanitizer_flags.h"
21 #include "sanitizer_common/sanitizer_platform.h"
22 
23 namespace __asan {
24 
25 struct PoisonRecord {
26   u32 stack_id;
27   u32 thread_id;
28   uptr begin;
29   uptr end;
30 };
31 
32 void AddPoisonRecord(const PoisonRecord& new_record);
33 bool FindPoisonRecord(uptr addr, PoisonRecord& match);
34 
35 void AcquirePoisonRecords();
36 void ReleasePoisonRecords();
37 
38 // Enable/disable memory poisoning.
39 void SetCanPoisonMemory(bool value);
40 bool CanPoisonMemory();
41 
42 // Poisons the shadow memory for "size" bytes starting from "addr".
43 void PoisonShadow(uptr addr, uptr size, u8 value);
44 
45 // Poisons the shadow memory for "redzone_size" bytes starting from
46 // "addr + size".
47 void PoisonShadowPartialRightRedzone(uptr addr,
48                                      uptr size,
49                                      uptr redzone_size,
50                                      u8 value);
51 
52 // Fast versions of PoisonShadow and PoisonShadowPartialRightRedzone that
53 // assume that memory addresses are properly aligned. Use in
54 // performance-critical code with care.
FastPoisonShadow(uptr aligned_beg,uptr aligned_size,u8 value)55 ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
56                                     u8 value) {
57   DCHECK(!value || CanPoisonMemory());
58 #if SANITIZER_FUCHSIA
59   __sanitizer_fill_shadow(aligned_beg, aligned_size, value,
60                           common_flags()->clear_shadow_mmap_threshold);
61 #else
62   uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
63   uptr shadow_end =
64       MEM_TO_SHADOW(aligned_beg + aligned_size - ASAN_SHADOW_GRANULARITY) + 1;
65   // FIXME: Page states are different on Windows, so using the same interface
66   // for mapping shadow and zeroing out pages doesn't "just work", so we should
67   // probably provide higher-level interface for these operations.
68   // For now, just memset on Windows.
69   if (value || SANITIZER_WINDOWS == 1 ||
70       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
71     REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
72   } else {
73     uptr page_size = GetPageSizeCached();
74     uptr page_beg = RoundUpTo(shadow_beg, page_size);
75     uptr page_end = RoundDownTo(shadow_end, page_size);
76 
77     if (page_beg >= page_end) {
78       REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
79     } else {
80       if (page_beg != shadow_beg) {
81         REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
82       }
83       if (page_end != shadow_end) {
84         REAL(memset)((void *)page_end, 0, shadow_end - page_end);
85       }
86       ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr);
87     }
88   }
89 #endif // SANITIZER_FUCHSIA
90 }
91 
FastPoisonShadowPartialRightRedzone(uptr aligned_addr,uptr size,uptr redzone_size,u8 value)92 ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
93     uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
94   DCHECK(CanPoisonMemory());
95   bool poison_partial = flags()->poison_partial;
96   u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
97   for (uptr i = 0; i < redzone_size; i += ASAN_SHADOW_GRANULARITY, shadow++) {
98     if (i + ASAN_SHADOW_GRANULARITY <= size) {
99       *shadow = 0;  // fully addressable
100     } else if (i >= size) {
101       *shadow =
102           (ASAN_SHADOW_GRANULARITY == 128) ? 0xff : value;  // unaddressable
103     } else {
104       // first size-i bytes are addressable
105       *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
106     }
107   }
108 }
109 
110 // Calls __sanitizer::ReleaseMemoryPagesToOS() on
111 // [MemToShadow(p), MemToShadow(p+size)].
112 void FlushUnneededASanShadowMemory(uptr p, uptr size);
113 
114 }  // namespace __asan
115 
116 #endif  // ASAN_POISONING_H
117