xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_poisoning.cpp (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1*68d75effSDimitry Andric //===-- asan_poisoning.cpp ------------------------------------------------===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric //
9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
10*68d75effSDimitry Andric //
11*68d75effSDimitry Andric // Shadow memory poisoning by ASan RTL and by user application.
12*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
13*68d75effSDimitry Andric 
14*68d75effSDimitry Andric #include "asan_poisoning.h"
15*68d75effSDimitry Andric #include "asan_report.h"
16*68d75effSDimitry Andric #include "asan_stack.h"
17*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
18*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
19*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
20*68d75effSDimitry Andric 
21*68d75effSDimitry Andric namespace __asan {
22*68d75effSDimitry Andric 
23*68d75effSDimitry Andric static atomic_uint8_t can_poison_memory;
24*68d75effSDimitry Andric 
25*68d75effSDimitry Andric void SetCanPoisonMemory(bool value) {
26*68d75effSDimitry Andric   atomic_store(&can_poison_memory, value, memory_order_release);
27*68d75effSDimitry Andric }
28*68d75effSDimitry Andric 
29*68d75effSDimitry Andric bool CanPoisonMemory() {
30*68d75effSDimitry Andric   return atomic_load(&can_poison_memory, memory_order_acquire);
31*68d75effSDimitry Andric }
32*68d75effSDimitry Andric 
33*68d75effSDimitry Andric void PoisonShadow(uptr addr, uptr size, u8 value) {
34*68d75effSDimitry Andric   if (value && !CanPoisonMemory()) return;
35*68d75effSDimitry Andric   CHECK(AddrIsAlignedByGranularity(addr));
36*68d75effSDimitry Andric   CHECK(AddrIsInMem(addr));
37*68d75effSDimitry Andric   CHECK(AddrIsAlignedByGranularity(addr + size));
38*68d75effSDimitry Andric   CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
39*68d75effSDimitry Andric   CHECK(REAL(memset));
40*68d75effSDimitry Andric   FastPoisonShadow(addr, size, value);
41*68d75effSDimitry Andric }
42*68d75effSDimitry Andric 
43*68d75effSDimitry Andric void PoisonShadowPartialRightRedzone(uptr addr,
44*68d75effSDimitry Andric                                      uptr size,
45*68d75effSDimitry Andric                                      uptr redzone_size,
46*68d75effSDimitry Andric                                      u8 value) {
47*68d75effSDimitry Andric   if (!CanPoisonMemory()) return;
48*68d75effSDimitry Andric   CHECK(AddrIsAlignedByGranularity(addr));
49*68d75effSDimitry Andric   CHECK(AddrIsInMem(addr));
50*68d75effSDimitry Andric   FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value);
51*68d75effSDimitry Andric }
52*68d75effSDimitry Andric 
53*68d75effSDimitry Andric struct ShadowSegmentEndpoint {
54*68d75effSDimitry Andric   u8 *chunk;
55*68d75effSDimitry Andric   s8 offset;  // in [0, SHADOW_GRANULARITY)
56*68d75effSDimitry Andric   s8 value;  // = *chunk;
57*68d75effSDimitry Andric 
58*68d75effSDimitry Andric   explicit ShadowSegmentEndpoint(uptr address) {
59*68d75effSDimitry Andric     chunk = (u8*)MemToShadow(address);
60*68d75effSDimitry Andric     offset = address & (SHADOW_GRANULARITY - 1);
61*68d75effSDimitry Andric     value = *chunk;
62*68d75effSDimitry Andric   }
63*68d75effSDimitry Andric };
64*68d75effSDimitry Andric 
65*68d75effSDimitry Andric void FlushUnneededASanShadowMemory(uptr p, uptr size) {
66*68d75effSDimitry Andric   // Since asan's mapping is compacting, the shadow chunk may be
67*68d75effSDimitry Andric   // not page-aligned, so we only flush the page-aligned portion.
68*68d75effSDimitry Andric   ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
69*68d75effSDimitry Andric }
70*68d75effSDimitry Andric 
71*68d75effSDimitry Andric void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
72*68d75effSDimitry Andric   uptr end = ptr + size;
73*68d75effSDimitry Andric   if (Verbosity()) {
74*68d75effSDimitry Andric     Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
75*68d75effSDimitry Andric            poison ? "" : "un", ptr, end, size);
76*68d75effSDimitry Andric     if (Verbosity() >= 2)
77*68d75effSDimitry Andric       PRINT_CURRENT_STACK();
78*68d75effSDimitry Andric   }
79*68d75effSDimitry Andric   CHECK(size);
80*68d75effSDimitry Andric   CHECK_LE(size, 4096);
81*68d75effSDimitry Andric   CHECK(IsAligned(end, SHADOW_GRANULARITY));
82*68d75effSDimitry Andric   if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
83*68d75effSDimitry Andric     *(u8 *)MemToShadow(ptr) =
84*68d75effSDimitry Andric         poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
85*68d75effSDimitry Andric     ptr |= SHADOW_GRANULARITY - 1;
86*68d75effSDimitry Andric     ptr++;
87*68d75effSDimitry Andric   }
88*68d75effSDimitry Andric   for (; ptr < end; ptr += SHADOW_GRANULARITY)
89*68d75effSDimitry Andric     *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
90*68d75effSDimitry Andric }
91*68d75effSDimitry Andric 
92*68d75effSDimitry Andric }  // namespace __asan
93*68d75effSDimitry Andric 
94*68d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1
95*68d75effSDimitry Andric using namespace __asan;
96*68d75effSDimitry Andric 
97*68d75effSDimitry Andric // Current implementation of __asan_(un)poison_memory_region doesn't check
98*68d75effSDimitry Andric // that user program (un)poisons the memory it owns. It poisons memory
99*68d75effSDimitry Andric // conservatively, and unpoisons progressively to make sure asan shadow
100*68d75effSDimitry Andric // mapping invariant is preserved (see detailed mapping description here:
101*68d75effSDimitry Andric // https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm).
102*68d75effSDimitry Andric //
103*68d75effSDimitry Andric // * if user asks to poison region [left, right), the program poisons
104*68d75effSDimitry Andric // at least [left, AlignDown(right)).
105*68d75effSDimitry Andric // * if user asks to unpoison region [left, right), the program unpoisons
106*68d75effSDimitry Andric // at most [AlignDown(left), right).
107*68d75effSDimitry Andric void __asan_poison_memory_region(void const volatile *addr, uptr size) {
108*68d75effSDimitry Andric   if (!flags()->allow_user_poisoning || size == 0) return;
109*68d75effSDimitry Andric   uptr beg_addr = (uptr)addr;
110*68d75effSDimitry Andric   uptr end_addr = beg_addr + size;
111*68d75effSDimitry Andric   VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr,
112*68d75effSDimitry Andric           (void *)end_addr);
113*68d75effSDimitry Andric   ShadowSegmentEndpoint beg(beg_addr);
114*68d75effSDimitry Andric   ShadowSegmentEndpoint end(end_addr);
115*68d75effSDimitry Andric   if (beg.chunk == end.chunk) {
116*68d75effSDimitry Andric     CHECK_LT(beg.offset, end.offset);
117*68d75effSDimitry Andric     s8 value = beg.value;
118*68d75effSDimitry Andric     CHECK_EQ(value, end.value);
119*68d75effSDimitry Andric     // We can only poison memory if the byte in end.offset is unaddressable.
120*68d75effSDimitry Andric     // No need to re-poison memory if it is poisoned already.
121*68d75effSDimitry Andric     if (value > 0 && value <= end.offset) {
122*68d75effSDimitry Andric       if (beg.offset > 0) {
123*68d75effSDimitry Andric         *beg.chunk = Min(value, beg.offset);
124*68d75effSDimitry Andric       } else {
125*68d75effSDimitry Andric         *beg.chunk = kAsanUserPoisonedMemoryMagic;
126*68d75effSDimitry Andric       }
127*68d75effSDimitry Andric     }
128*68d75effSDimitry Andric     return;
129*68d75effSDimitry Andric   }
130*68d75effSDimitry Andric   CHECK_LT(beg.chunk, end.chunk);
131*68d75effSDimitry Andric   if (beg.offset > 0) {
132*68d75effSDimitry Andric     // Mark bytes from beg.offset as unaddressable.
133*68d75effSDimitry Andric     if (beg.value == 0) {
134*68d75effSDimitry Andric       *beg.chunk = beg.offset;
135*68d75effSDimitry Andric     } else {
136*68d75effSDimitry Andric       *beg.chunk = Min(beg.value, beg.offset);
137*68d75effSDimitry Andric     }
138*68d75effSDimitry Andric     beg.chunk++;
139*68d75effSDimitry Andric   }
140*68d75effSDimitry Andric   REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk);
141*68d75effSDimitry Andric   // Poison if byte in end.offset is unaddressable.
142*68d75effSDimitry Andric   if (end.value > 0 && end.value <= end.offset) {
143*68d75effSDimitry Andric     *end.chunk = kAsanUserPoisonedMemoryMagic;
144*68d75effSDimitry Andric   }
145*68d75effSDimitry Andric }
146*68d75effSDimitry Andric 
147*68d75effSDimitry Andric void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
148*68d75effSDimitry Andric   if (!flags()->allow_user_poisoning || size == 0) return;
149*68d75effSDimitry Andric   uptr beg_addr = (uptr)addr;
150*68d75effSDimitry Andric   uptr end_addr = beg_addr + size;
151*68d75effSDimitry Andric   VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr,
152*68d75effSDimitry Andric           (void *)end_addr);
153*68d75effSDimitry Andric   ShadowSegmentEndpoint beg(beg_addr);
154*68d75effSDimitry Andric   ShadowSegmentEndpoint end(end_addr);
155*68d75effSDimitry Andric   if (beg.chunk == end.chunk) {
156*68d75effSDimitry Andric     CHECK_LT(beg.offset, end.offset);
157*68d75effSDimitry Andric     s8 value = beg.value;
158*68d75effSDimitry Andric     CHECK_EQ(value, end.value);
159*68d75effSDimitry Andric     // We unpoison memory bytes up to enbytes up to end.offset if it is not
160*68d75effSDimitry Andric     // unpoisoned already.
161*68d75effSDimitry Andric     if (value != 0) {
162*68d75effSDimitry Andric       *beg.chunk = Max(value, end.offset);
163*68d75effSDimitry Andric     }
164*68d75effSDimitry Andric     return;
165*68d75effSDimitry Andric   }
166*68d75effSDimitry Andric   CHECK_LT(beg.chunk, end.chunk);
167*68d75effSDimitry Andric   if (beg.offset > 0) {
168*68d75effSDimitry Andric     *beg.chunk = 0;
169*68d75effSDimitry Andric     beg.chunk++;
170*68d75effSDimitry Andric   }
171*68d75effSDimitry Andric   REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk);
172*68d75effSDimitry Andric   if (end.offset > 0 && end.value != 0) {
173*68d75effSDimitry Andric     *end.chunk = Max(end.value, end.offset);
174*68d75effSDimitry Andric   }
175*68d75effSDimitry Andric }
176*68d75effSDimitry Andric 
177*68d75effSDimitry Andric int __asan_address_is_poisoned(void const volatile *addr) {
178*68d75effSDimitry Andric   return __asan::AddressIsPoisoned((uptr)addr);
179*68d75effSDimitry Andric }
180*68d75effSDimitry Andric 
181*68d75effSDimitry Andric uptr __asan_region_is_poisoned(uptr beg, uptr size) {
182*68d75effSDimitry Andric   if (!size) return 0;
183*68d75effSDimitry Andric   uptr end = beg + size;
184*68d75effSDimitry Andric   if (SANITIZER_MYRIAD2) {
185*68d75effSDimitry Andric     // On Myriad, address not in DRAM range need to be treated as
186*68d75effSDimitry Andric     // unpoisoned.
187*68d75effSDimitry Andric     if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0;
188*68d75effSDimitry Andric     if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0;
189*68d75effSDimitry Andric   } else {
190*68d75effSDimitry Andric     if (!AddrIsInMem(beg)) return beg;
191*68d75effSDimitry Andric     if (!AddrIsInMem(end)) return end;
192*68d75effSDimitry Andric   }
193*68d75effSDimitry Andric   CHECK_LT(beg, end);
194*68d75effSDimitry Andric   uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY);
195*68d75effSDimitry Andric   uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY);
196*68d75effSDimitry Andric   uptr shadow_beg = MemToShadow(aligned_b);
197*68d75effSDimitry Andric   uptr shadow_end = MemToShadow(aligned_e);
198*68d75effSDimitry Andric   // First check the first and the last application bytes,
199*68d75effSDimitry Andric   // then check the SHADOW_GRANULARITY-aligned region by calling
200*68d75effSDimitry Andric   // mem_is_zero on the corresponding shadow.
201*68d75effSDimitry Andric   if (!__asan::AddressIsPoisoned(beg) &&
202*68d75effSDimitry Andric       !__asan::AddressIsPoisoned(end - 1) &&
203*68d75effSDimitry Andric       (shadow_end <= shadow_beg ||
204*68d75effSDimitry Andric        __sanitizer::mem_is_zero((const char *)shadow_beg,
205*68d75effSDimitry Andric                                 shadow_end - shadow_beg)))
206*68d75effSDimitry Andric     return 0;
207*68d75effSDimitry Andric   // The fast check failed, so we have a poisoned byte somewhere.
208*68d75effSDimitry Andric   // Find it slowly.
209*68d75effSDimitry Andric   for (; beg < end; beg++)
210*68d75effSDimitry Andric     if (__asan::AddressIsPoisoned(beg))
211*68d75effSDimitry Andric       return beg;
212*68d75effSDimitry Andric   UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found");
213*68d75effSDimitry Andric   return 0;
214*68d75effSDimitry Andric }
215*68d75effSDimitry Andric 
216*68d75effSDimitry Andric #define CHECK_SMALL_REGION(p, size, isWrite)                  \
217*68d75effSDimitry Andric   do {                                                        \
218*68d75effSDimitry Andric     uptr __p = reinterpret_cast<uptr>(p);                     \
219*68d75effSDimitry Andric     uptr __size = size;                                       \
220*68d75effSDimitry Andric     if (UNLIKELY(__asan::AddressIsPoisoned(__p) ||            \
221*68d75effSDimitry Andric         __asan::AddressIsPoisoned(__p + __size - 1))) {       \
222*68d75effSDimitry Andric       GET_CURRENT_PC_BP_SP;                                   \
223*68d75effSDimitry Andric       uptr __bad = __asan_region_is_poisoned(__p, __size);    \
224*68d75effSDimitry Andric       __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\
225*68d75effSDimitry Andric     }                                                         \
226*68d75effSDimitry Andric   } while (false)
227*68d75effSDimitry Andric 
228*68d75effSDimitry Andric 
229*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
230*68d75effSDimitry Andric u16 __sanitizer_unaligned_load16(const uu16 *p) {
231*68d75effSDimitry Andric   CHECK_SMALL_REGION(p, sizeof(*p), false);
232*68d75effSDimitry Andric   return *p;
233*68d75effSDimitry Andric }
234*68d75effSDimitry Andric 
235*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
236*68d75effSDimitry Andric u32 __sanitizer_unaligned_load32(const uu32 *p) {
237*68d75effSDimitry Andric   CHECK_SMALL_REGION(p, sizeof(*p), false);
238*68d75effSDimitry Andric   return *p;
239*68d75effSDimitry Andric }
240*68d75effSDimitry Andric 
241*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
242*68d75effSDimitry Andric u64 __sanitizer_unaligned_load64(const uu64 *p) {
243*68d75effSDimitry Andric   CHECK_SMALL_REGION(p, sizeof(*p), false);
244*68d75effSDimitry Andric   return *p;
245*68d75effSDimitry Andric }
246*68d75effSDimitry Andric 
247*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
248*68d75effSDimitry Andric void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
249*68d75effSDimitry Andric   CHECK_SMALL_REGION(p, sizeof(*p), true);
250*68d75effSDimitry Andric   *p = x;
251*68d75effSDimitry Andric }
252*68d75effSDimitry Andric 
253*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
254*68d75effSDimitry Andric void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
255*68d75effSDimitry Andric   CHECK_SMALL_REGION(p, sizeof(*p), true);
256*68d75effSDimitry Andric   *p = x;
257*68d75effSDimitry Andric }
258*68d75effSDimitry Andric 
259*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
260*68d75effSDimitry Andric void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
261*68d75effSDimitry Andric   CHECK_SMALL_REGION(p, sizeof(*p), true);
262*68d75effSDimitry Andric   *p = x;
263*68d75effSDimitry Andric }
264*68d75effSDimitry Andric 
265*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
266*68d75effSDimitry Andric void __asan_poison_cxx_array_cookie(uptr p) {
267*68d75effSDimitry Andric   if (SANITIZER_WORDSIZE != 64) return;
268*68d75effSDimitry Andric   if (!flags()->poison_array_cookie) return;
269*68d75effSDimitry Andric   uptr s = MEM_TO_SHADOW(p);
270*68d75effSDimitry Andric   *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic;
271*68d75effSDimitry Andric }
272*68d75effSDimitry Andric 
273*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
274*68d75effSDimitry Andric uptr __asan_load_cxx_array_cookie(uptr *p) {
275*68d75effSDimitry Andric   if (SANITIZER_WORDSIZE != 64) return *p;
276*68d75effSDimitry Andric   if (!flags()->poison_array_cookie) return *p;
277*68d75effSDimitry Andric   uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p));
278*68d75effSDimitry Andric   u8 sval = *reinterpret_cast<u8*>(s);
279*68d75effSDimitry Andric   if (sval == kAsanArrayCookieMagic) return *p;
280*68d75effSDimitry Andric   // If sval is not kAsanArrayCookieMagic it can only be freed memory,
281*68d75effSDimitry Andric   // which means that we are going to get double-free. So, return 0 to avoid
282*68d75effSDimitry Andric   // infinite loop of destructors. We don't want to report a double-free here
283*68d75effSDimitry Andric   // though, so print a warning just in case.
284*68d75effSDimitry Andric   // CHECK_EQ(sval, kAsanHeapFreeMagic);
285*68d75effSDimitry Andric   if (sval == kAsanHeapFreeMagic) {
286*68d75effSDimitry Andric     Report("AddressSanitizer: loaded array cookie from free-d memory; "
287*68d75effSDimitry Andric            "expect a double-free report\n");
288*68d75effSDimitry Andric     return 0;
289*68d75effSDimitry Andric   }
290*68d75effSDimitry Andric   // The cookie may remain unpoisoned if e.g. it comes from a custom
291*68d75effSDimitry Andric   // operator new defined inside a class.
292*68d75effSDimitry Andric   return *p;
293*68d75effSDimitry Andric }
294*68d75effSDimitry Andric 
295*68d75effSDimitry Andric // This is a simplified version of __asan_(un)poison_memory_region, which
296*68d75effSDimitry Andric // assumes that left border of region to be poisoned is properly aligned.
297*68d75effSDimitry Andric static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
298*68d75effSDimitry Andric   if (size == 0) return;
299*68d75effSDimitry Andric   uptr aligned_size = size & ~(SHADOW_GRANULARITY - 1);
300*68d75effSDimitry Andric   PoisonShadow(addr, aligned_size,
301*68d75effSDimitry Andric                do_poison ? kAsanStackUseAfterScopeMagic : 0);
302*68d75effSDimitry Andric   if (size == aligned_size)
303*68d75effSDimitry Andric     return;
304*68d75effSDimitry Andric   s8 end_offset = (s8)(size - aligned_size);
305*68d75effSDimitry Andric   s8* shadow_end = (s8*)MemToShadow(addr + aligned_size);
306*68d75effSDimitry Andric   s8 end_value = *shadow_end;
307*68d75effSDimitry Andric   if (do_poison) {
308*68d75effSDimitry Andric     // If possible, mark all the bytes mapping to last shadow byte as
309*68d75effSDimitry Andric     // unaddressable.
310*68d75effSDimitry Andric     if (end_value > 0 && end_value <= end_offset)
311*68d75effSDimitry Andric       *shadow_end = (s8)kAsanStackUseAfterScopeMagic;
312*68d75effSDimitry Andric   } else {
313*68d75effSDimitry Andric     // If necessary, mark few first bytes mapping to last shadow byte
314*68d75effSDimitry Andric     // as addressable
315*68d75effSDimitry Andric     if (end_value != 0)
316*68d75effSDimitry Andric       *shadow_end = Max(end_value, end_offset);
317*68d75effSDimitry Andric   }
318*68d75effSDimitry Andric }
319*68d75effSDimitry Andric 
320*68d75effSDimitry Andric void __asan_set_shadow_00(uptr addr, uptr size) {
321*68d75effSDimitry Andric   REAL(memset)((void *)addr, 0, size);
322*68d75effSDimitry Andric }
323*68d75effSDimitry Andric 
324*68d75effSDimitry Andric void __asan_set_shadow_f1(uptr addr, uptr size) {
325*68d75effSDimitry Andric   REAL(memset)((void *)addr, 0xf1, size);
326*68d75effSDimitry Andric }
327*68d75effSDimitry Andric 
328*68d75effSDimitry Andric void __asan_set_shadow_f2(uptr addr, uptr size) {
329*68d75effSDimitry Andric   REAL(memset)((void *)addr, 0xf2, size);
330*68d75effSDimitry Andric }
331*68d75effSDimitry Andric 
332*68d75effSDimitry Andric void __asan_set_shadow_f3(uptr addr, uptr size) {
333*68d75effSDimitry Andric   REAL(memset)((void *)addr, 0xf3, size);
334*68d75effSDimitry Andric }
335*68d75effSDimitry Andric 
336*68d75effSDimitry Andric void __asan_set_shadow_f5(uptr addr, uptr size) {
337*68d75effSDimitry Andric   REAL(memset)((void *)addr, 0xf5, size);
338*68d75effSDimitry Andric }
339*68d75effSDimitry Andric 
340*68d75effSDimitry Andric void __asan_set_shadow_f8(uptr addr, uptr size) {
341*68d75effSDimitry Andric   REAL(memset)((void *)addr, 0xf8, size);
342*68d75effSDimitry Andric }
343*68d75effSDimitry Andric 
344*68d75effSDimitry Andric void __asan_poison_stack_memory(uptr addr, uptr size) {
345*68d75effSDimitry Andric   VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
346*68d75effSDimitry Andric   PoisonAlignedStackMemory(addr, size, true);
347*68d75effSDimitry Andric }
348*68d75effSDimitry Andric 
349*68d75effSDimitry Andric void __asan_unpoison_stack_memory(uptr addr, uptr size) {
350*68d75effSDimitry Andric   VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size);
351*68d75effSDimitry Andric   PoisonAlignedStackMemory(addr, size, false);
352*68d75effSDimitry Andric }
353*68d75effSDimitry Andric 
354*68d75effSDimitry Andric void __sanitizer_annotate_contiguous_container(const void *beg_p,
355*68d75effSDimitry Andric                                                const void *end_p,
356*68d75effSDimitry Andric                                                const void *old_mid_p,
357*68d75effSDimitry Andric                                                const void *new_mid_p) {
358*68d75effSDimitry Andric   if (!flags()->detect_container_overflow) return;
359*68d75effSDimitry Andric   VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
360*68d75effSDimitry Andric           new_mid_p);
361*68d75effSDimitry Andric   uptr beg = reinterpret_cast<uptr>(beg_p);
362*68d75effSDimitry Andric   uptr end = reinterpret_cast<uptr>(end_p);
363*68d75effSDimitry Andric   uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
364*68d75effSDimitry Andric   uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
365*68d75effSDimitry Andric   uptr granularity = SHADOW_GRANULARITY;
366*68d75effSDimitry Andric   if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
367*68d75effSDimitry Andric         IsAligned(beg, granularity))) {
368*68d75effSDimitry Andric     GET_STACK_TRACE_FATAL_HERE;
369*68d75effSDimitry Andric     ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
370*68d75effSDimitry Andric                                                  &stack);
371*68d75effSDimitry Andric   }
372*68d75effSDimitry Andric   CHECK_LE(end - beg,
373*68d75effSDimitry Andric            FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
374*68d75effSDimitry Andric 
375*68d75effSDimitry Andric   uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
376*68d75effSDimitry Andric   uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
377*68d75effSDimitry Andric   uptr d1 = RoundDownTo(old_mid, granularity);
378*68d75effSDimitry Andric   // uptr d2 = RoundUpTo(old_mid, granularity);
379*68d75effSDimitry Andric   // Currently we should be in this state:
380*68d75effSDimitry Andric   // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
381*68d75effSDimitry Andric   // Make a quick sanity check that we are indeed in this state.
382*68d75effSDimitry Andric   //
383*68d75effSDimitry Andric   // FIXME: Two of these three checks are disabled until we fix
384*68d75effSDimitry Andric   // https://github.com/google/sanitizers/issues/258.
385*68d75effSDimitry Andric   // if (d1 != d2)
386*68d75effSDimitry Andric   //  CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
387*68d75effSDimitry Andric   if (a + granularity <= d1)
388*68d75effSDimitry Andric     CHECK_EQ(*(u8*)MemToShadow(a), 0);
389*68d75effSDimitry Andric   // if (d2 + granularity <= c && c <= end)
390*68d75effSDimitry Andric   //   CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
391*68d75effSDimitry Andric   //            kAsanContiguousContainerOOBMagic);
392*68d75effSDimitry Andric 
393*68d75effSDimitry Andric   uptr b1 = RoundDownTo(new_mid, granularity);
394*68d75effSDimitry Andric   uptr b2 = RoundUpTo(new_mid, granularity);
395*68d75effSDimitry Andric   // New state:
396*68d75effSDimitry Andric   // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
397*68d75effSDimitry Andric   PoisonShadow(a, b1 - a, 0);
398*68d75effSDimitry Andric   PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
399*68d75effSDimitry Andric   if (b1 != b2) {
400*68d75effSDimitry Andric     CHECK_EQ(b2 - b1, granularity);
401*68d75effSDimitry Andric     *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
402*68d75effSDimitry Andric   }
403*68d75effSDimitry Andric }
404*68d75effSDimitry Andric 
405*68d75effSDimitry Andric const void *__sanitizer_contiguous_container_find_bad_address(
406*68d75effSDimitry Andric     const void *beg_p, const void *mid_p, const void *end_p) {
407*68d75effSDimitry Andric   if (!flags()->detect_container_overflow)
408*68d75effSDimitry Andric     return nullptr;
409*68d75effSDimitry Andric   uptr beg = reinterpret_cast<uptr>(beg_p);
410*68d75effSDimitry Andric   uptr end = reinterpret_cast<uptr>(end_p);
411*68d75effSDimitry Andric   uptr mid = reinterpret_cast<uptr>(mid_p);
412*68d75effSDimitry Andric   CHECK_LE(beg, mid);
413*68d75effSDimitry Andric   CHECK_LE(mid, end);
414*68d75effSDimitry Andric   // Check some bytes starting from beg, some bytes around mid, and some bytes
415*68d75effSDimitry Andric   // ending with end.
416*68d75effSDimitry Andric   uptr kMaxRangeToCheck = 32;
417*68d75effSDimitry Andric   uptr r1_beg = beg;
418*68d75effSDimitry Andric   uptr r1_end = Min(beg + kMaxRangeToCheck, mid);
419*68d75effSDimitry Andric   uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
420*68d75effSDimitry Andric   uptr r2_end = Min(end, mid + kMaxRangeToCheck);
421*68d75effSDimitry Andric   uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
422*68d75effSDimitry Andric   uptr r3_end = end;
423*68d75effSDimitry Andric   for (uptr i = r1_beg; i < r1_end; i++)
424*68d75effSDimitry Andric     if (AddressIsPoisoned(i))
425*68d75effSDimitry Andric       return reinterpret_cast<const void *>(i);
426*68d75effSDimitry Andric   for (uptr i = r2_beg; i < mid; i++)
427*68d75effSDimitry Andric     if (AddressIsPoisoned(i))
428*68d75effSDimitry Andric       return reinterpret_cast<const void *>(i);
429*68d75effSDimitry Andric   for (uptr i = mid; i < r2_end; i++)
430*68d75effSDimitry Andric     if (!AddressIsPoisoned(i))
431*68d75effSDimitry Andric       return reinterpret_cast<const void *>(i);
432*68d75effSDimitry Andric   for (uptr i = r3_beg; i < r3_end; i++)
433*68d75effSDimitry Andric     if (!AddressIsPoisoned(i))
434*68d75effSDimitry Andric       return reinterpret_cast<const void *>(i);
435*68d75effSDimitry Andric   return nullptr;
436*68d75effSDimitry Andric }
437*68d75effSDimitry Andric 
438*68d75effSDimitry Andric int __sanitizer_verify_contiguous_container(const void *beg_p,
439*68d75effSDimitry Andric                                             const void *mid_p,
440*68d75effSDimitry Andric                                             const void *end_p) {
441*68d75effSDimitry Andric   return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p,
442*68d75effSDimitry Andric                                                            end_p) == nullptr;
443*68d75effSDimitry Andric }
444*68d75effSDimitry Andric 
445*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
446*68d75effSDimitry Andric void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
447*68d75effSDimitry Andric   AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
448*68d75effSDimitry Andric }
449*68d75effSDimitry Andric 
450*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
451*68d75effSDimitry Andric void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
452*68d75effSDimitry Andric   AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
453*68d75effSDimitry Andric }
454*68d75effSDimitry Andric 
455*68d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1
456*68d75effSDimitry Andric namespace __lsan {
457*68d75effSDimitry Andric bool WordIsPoisoned(uptr addr) {
458*68d75effSDimitry Andric   return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0);
459*68d75effSDimitry Andric }
460*68d75effSDimitry Andric }
461