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