168d75effSDimitry Andric //===-- asan_poisoning.cpp ------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Shadow memory poisoning by ASan RTL and by user application. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "asan_poisoning.h" 1568d75effSDimitry Andric #include "asan_report.h" 1668d75effSDimitry Andric #include "asan_stack.h" 1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h" 1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h" 1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h" 2068d75effSDimitry Andric 2168d75effSDimitry Andric namespace __asan { 2268d75effSDimitry Andric 2368d75effSDimitry Andric static atomic_uint8_t can_poison_memory; 2468d75effSDimitry Andric 2568d75effSDimitry Andric void SetCanPoisonMemory(bool value) { 2668d75effSDimitry Andric atomic_store(&can_poison_memory, value, memory_order_release); 2768d75effSDimitry Andric } 2868d75effSDimitry Andric 2968d75effSDimitry Andric bool CanPoisonMemory() { 3068d75effSDimitry Andric return atomic_load(&can_poison_memory, memory_order_acquire); 3168d75effSDimitry Andric } 3268d75effSDimitry Andric 3368d75effSDimitry Andric void PoisonShadow(uptr addr, uptr size, u8 value) { 3468d75effSDimitry Andric if (value && !CanPoisonMemory()) return; 3568d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(addr)); 3668d75effSDimitry Andric CHECK(AddrIsInMem(addr)); 3768d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(addr + size)); 3868d75effSDimitry Andric CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY)); 3968d75effSDimitry Andric CHECK(REAL(memset)); 4068d75effSDimitry Andric FastPoisonShadow(addr, size, value); 4168d75effSDimitry Andric } 4268d75effSDimitry Andric 4368d75effSDimitry Andric void PoisonShadowPartialRightRedzone(uptr addr, 4468d75effSDimitry Andric uptr size, 4568d75effSDimitry Andric uptr redzone_size, 4668d75effSDimitry Andric u8 value) { 4768d75effSDimitry Andric if (!CanPoisonMemory()) return; 4868d75effSDimitry Andric CHECK(AddrIsAlignedByGranularity(addr)); 4968d75effSDimitry Andric CHECK(AddrIsInMem(addr)); 5068d75effSDimitry Andric FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value); 5168d75effSDimitry Andric } 5268d75effSDimitry Andric 5368d75effSDimitry Andric struct ShadowSegmentEndpoint { 5468d75effSDimitry Andric u8 *chunk; 5568d75effSDimitry Andric s8 offset; // in [0, SHADOW_GRANULARITY) 5668d75effSDimitry Andric s8 value; // = *chunk; 5768d75effSDimitry Andric 5868d75effSDimitry Andric explicit ShadowSegmentEndpoint(uptr address) { 5968d75effSDimitry Andric chunk = (u8*)MemToShadow(address); 6068d75effSDimitry Andric offset = address & (SHADOW_GRANULARITY - 1); 6168d75effSDimitry Andric value = *chunk; 6268d75effSDimitry Andric } 6368d75effSDimitry Andric }; 6468d75effSDimitry Andric 6568d75effSDimitry Andric void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { 6668d75effSDimitry Andric uptr end = ptr + size; 6768d75effSDimitry Andric if (Verbosity()) { 6868d75effSDimitry Andric Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n", 69*349cc55cSDimitry Andric poison ? "" : "un", (void *)ptr, (void *)end, size); 7068d75effSDimitry Andric if (Verbosity() >= 2) 7168d75effSDimitry Andric PRINT_CURRENT_STACK(); 7268d75effSDimitry Andric } 7368d75effSDimitry Andric CHECK(size); 7468d75effSDimitry Andric CHECK_LE(size, 4096); 7568d75effSDimitry Andric CHECK(IsAligned(end, SHADOW_GRANULARITY)); 7668d75effSDimitry Andric if (!IsAligned(ptr, SHADOW_GRANULARITY)) { 7768d75effSDimitry Andric *(u8 *)MemToShadow(ptr) = 7868d75effSDimitry Andric poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0; 7968d75effSDimitry Andric ptr |= SHADOW_GRANULARITY - 1; 8068d75effSDimitry Andric ptr++; 8168d75effSDimitry Andric } 8268d75effSDimitry Andric for (; ptr < end; ptr += SHADOW_GRANULARITY) 8368d75effSDimitry Andric *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0; 8468d75effSDimitry Andric } 8568d75effSDimitry Andric 8668d75effSDimitry Andric } // namespace __asan 8768d75effSDimitry Andric 8868d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1 8968d75effSDimitry Andric using namespace __asan; 9068d75effSDimitry Andric 9168d75effSDimitry Andric // Current implementation of __asan_(un)poison_memory_region doesn't check 9268d75effSDimitry Andric // that user program (un)poisons the memory it owns. It poisons memory 9368d75effSDimitry Andric // conservatively, and unpoisons progressively to make sure asan shadow 9468d75effSDimitry Andric // mapping invariant is preserved (see detailed mapping description here: 9568d75effSDimitry Andric // https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm). 9668d75effSDimitry Andric // 9768d75effSDimitry Andric // * if user asks to poison region [left, right), the program poisons 9868d75effSDimitry Andric // at least [left, AlignDown(right)). 9968d75effSDimitry Andric // * if user asks to unpoison region [left, right), the program unpoisons 10068d75effSDimitry Andric // at most [AlignDown(left), right). 10168d75effSDimitry Andric void __asan_poison_memory_region(void const volatile *addr, uptr size) { 10268d75effSDimitry Andric if (!flags()->allow_user_poisoning || size == 0) return; 10368d75effSDimitry Andric uptr beg_addr = (uptr)addr; 10468d75effSDimitry Andric uptr end_addr = beg_addr + size; 10568d75effSDimitry Andric VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, 10668d75effSDimitry Andric (void *)end_addr); 10768d75effSDimitry Andric ShadowSegmentEndpoint beg(beg_addr); 10868d75effSDimitry Andric ShadowSegmentEndpoint end(end_addr); 10968d75effSDimitry Andric if (beg.chunk == end.chunk) { 11068d75effSDimitry Andric CHECK_LT(beg.offset, end.offset); 11168d75effSDimitry Andric s8 value = beg.value; 11268d75effSDimitry Andric CHECK_EQ(value, end.value); 11368d75effSDimitry Andric // We can only poison memory if the byte in end.offset is unaddressable. 11468d75effSDimitry Andric // No need to re-poison memory if it is poisoned already. 11568d75effSDimitry Andric if (value > 0 && value <= end.offset) { 11668d75effSDimitry Andric if (beg.offset > 0) { 11768d75effSDimitry Andric *beg.chunk = Min(value, beg.offset); 11868d75effSDimitry Andric } else { 11968d75effSDimitry Andric *beg.chunk = kAsanUserPoisonedMemoryMagic; 12068d75effSDimitry Andric } 12168d75effSDimitry Andric } 12268d75effSDimitry Andric return; 12368d75effSDimitry Andric } 12468d75effSDimitry Andric CHECK_LT(beg.chunk, end.chunk); 12568d75effSDimitry Andric if (beg.offset > 0) { 12668d75effSDimitry Andric // Mark bytes from beg.offset as unaddressable. 12768d75effSDimitry Andric if (beg.value == 0) { 12868d75effSDimitry Andric *beg.chunk = beg.offset; 12968d75effSDimitry Andric } else { 13068d75effSDimitry Andric *beg.chunk = Min(beg.value, beg.offset); 13168d75effSDimitry Andric } 13268d75effSDimitry Andric beg.chunk++; 13368d75effSDimitry Andric } 13468d75effSDimitry Andric REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk); 13568d75effSDimitry Andric // Poison if byte in end.offset is unaddressable. 13668d75effSDimitry Andric if (end.value > 0 && end.value <= end.offset) { 13768d75effSDimitry Andric *end.chunk = kAsanUserPoisonedMemoryMagic; 13868d75effSDimitry Andric } 13968d75effSDimitry Andric } 14068d75effSDimitry Andric 14168d75effSDimitry Andric void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { 14268d75effSDimitry Andric if (!flags()->allow_user_poisoning || size == 0) return; 14368d75effSDimitry Andric uptr beg_addr = (uptr)addr; 14468d75effSDimitry Andric uptr end_addr = beg_addr + size; 14568d75effSDimitry Andric VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, 14668d75effSDimitry Andric (void *)end_addr); 14768d75effSDimitry Andric ShadowSegmentEndpoint beg(beg_addr); 14868d75effSDimitry Andric ShadowSegmentEndpoint end(end_addr); 14968d75effSDimitry Andric if (beg.chunk == end.chunk) { 15068d75effSDimitry Andric CHECK_LT(beg.offset, end.offset); 15168d75effSDimitry Andric s8 value = beg.value; 15268d75effSDimitry Andric CHECK_EQ(value, end.value); 15368d75effSDimitry Andric // We unpoison memory bytes up to enbytes up to end.offset if it is not 15468d75effSDimitry Andric // unpoisoned already. 15568d75effSDimitry Andric if (value != 0) { 15668d75effSDimitry Andric *beg.chunk = Max(value, end.offset); 15768d75effSDimitry Andric } 15868d75effSDimitry Andric return; 15968d75effSDimitry Andric } 16068d75effSDimitry Andric CHECK_LT(beg.chunk, end.chunk); 16168d75effSDimitry Andric if (beg.offset > 0) { 16268d75effSDimitry Andric *beg.chunk = 0; 16368d75effSDimitry Andric beg.chunk++; 16468d75effSDimitry Andric } 16568d75effSDimitry Andric REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk); 16668d75effSDimitry Andric if (end.offset > 0 && end.value != 0) { 16768d75effSDimitry Andric *end.chunk = Max(end.value, end.offset); 16868d75effSDimitry Andric } 16968d75effSDimitry Andric } 17068d75effSDimitry Andric 17168d75effSDimitry Andric int __asan_address_is_poisoned(void const volatile *addr) { 17268d75effSDimitry Andric return __asan::AddressIsPoisoned((uptr)addr); 17368d75effSDimitry Andric } 17468d75effSDimitry Andric 17568d75effSDimitry Andric uptr __asan_region_is_poisoned(uptr beg, uptr size) { 176fe6060f1SDimitry Andric if (!size) 177fe6060f1SDimitry Andric return 0; 17868d75effSDimitry Andric uptr end = beg + size; 179fe6060f1SDimitry Andric if (!AddrIsInMem(beg)) 180fe6060f1SDimitry Andric return beg; 181fe6060f1SDimitry Andric if (!AddrIsInMem(end)) 182fe6060f1SDimitry Andric return end; 18368d75effSDimitry Andric CHECK_LT(beg, end); 18468d75effSDimitry Andric uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY); 18568d75effSDimitry Andric uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY); 18668d75effSDimitry Andric uptr shadow_beg = MemToShadow(aligned_b); 18768d75effSDimitry Andric uptr shadow_end = MemToShadow(aligned_e); 18868d75effSDimitry Andric // First check the first and the last application bytes, 18968d75effSDimitry Andric // then check the SHADOW_GRANULARITY-aligned region by calling 19068d75effSDimitry Andric // mem_is_zero on the corresponding shadow. 191fe6060f1SDimitry Andric if (!__asan::AddressIsPoisoned(beg) && !__asan::AddressIsPoisoned(end - 1) && 19268d75effSDimitry Andric (shadow_end <= shadow_beg || 19368d75effSDimitry Andric __sanitizer::mem_is_zero((const char *)shadow_beg, 19468d75effSDimitry Andric shadow_end - shadow_beg))) 19568d75effSDimitry Andric return 0; 19668d75effSDimitry Andric // The fast check failed, so we have a poisoned byte somewhere. 19768d75effSDimitry Andric // Find it slowly. 19868d75effSDimitry Andric for (; beg < end; beg++) 19968d75effSDimitry Andric if (__asan::AddressIsPoisoned(beg)) 20068d75effSDimitry Andric return beg; 20168d75effSDimitry Andric UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found"); 20268d75effSDimitry Andric return 0; 20368d75effSDimitry Andric } 20468d75effSDimitry Andric 20568d75effSDimitry Andric #define CHECK_SMALL_REGION(p, size, isWrite) \ 20668d75effSDimitry Andric do { \ 20768d75effSDimitry Andric uptr __p = reinterpret_cast<uptr>(p); \ 20868d75effSDimitry Andric uptr __size = size; \ 20968d75effSDimitry Andric if (UNLIKELY(__asan::AddressIsPoisoned(__p) || \ 21068d75effSDimitry Andric __asan::AddressIsPoisoned(__p + __size - 1))) { \ 21168d75effSDimitry Andric GET_CURRENT_PC_BP_SP; \ 21268d75effSDimitry Andric uptr __bad = __asan_region_is_poisoned(__p, __size); \ 21368d75effSDimitry Andric __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\ 21468d75effSDimitry Andric } \ 21568d75effSDimitry Andric } while (false) 21668d75effSDimitry Andric 21768d75effSDimitry Andric 21868d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 21968d75effSDimitry Andric u16 __sanitizer_unaligned_load16(const uu16 *p) { 22068d75effSDimitry Andric CHECK_SMALL_REGION(p, sizeof(*p), false); 22168d75effSDimitry Andric return *p; 22268d75effSDimitry Andric } 22368d75effSDimitry Andric 22468d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 22568d75effSDimitry Andric u32 __sanitizer_unaligned_load32(const uu32 *p) { 22668d75effSDimitry Andric CHECK_SMALL_REGION(p, sizeof(*p), false); 22768d75effSDimitry Andric return *p; 22868d75effSDimitry Andric } 22968d75effSDimitry Andric 23068d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 23168d75effSDimitry Andric u64 __sanitizer_unaligned_load64(const uu64 *p) { 23268d75effSDimitry Andric CHECK_SMALL_REGION(p, sizeof(*p), false); 23368d75effSDimitry Andric return *p; 23468d75effSDimitry Andric } 23568d75effSDimitry Andric 23668d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 23768d75effSDimitry Andric void __sanitizer_unaligned_store16(uu16 *p, u16 x) { 23868d75effSDimitry Andric CHECK_SMALL_REGION(p, sizeof(*p), true); 23968d75effSDimitry Andric *p = x; 24068d75effSDimitry Andric } 24168d75effSDimitry Andric 24268d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 24368d75effSDimitry Andric void __sanitizer_unaligned_store32(uu32 *p, u32 x) { 24468d75effSDimitry Andric CHECK_SMALL_REGION(p, sizeof(*p), true); 24568d75effSDimitry Andric *p = x; 24668d75effSDimitry Andric } 24768d75effSDimitry Andric 24868d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 24968d75effSDimitry Andric void __sanitizer_unaligned_store64(uu64 *p, u64 x) { 25068d75effSDimitry Andric CHECK_SMALL_REGION(p, sizeof(*p), true); 25168d75effSDimitry Andric *p = x; 25268d75effSDimitry Andric } 25368d75effSDimitry Andric 25468d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 25568d75effSDimitry Andric void __asan_poison_cxx_array_cookie(uptr p) { 25668d75effSDimitry Andric if (SANITIZER_WORDSIZE != 64) return; 25768d75effSDimitry Andric if (!flags()->poison_array_cookie) return; 25868d75effSDimitry Andric uptr s = MEM_TO_SHADOW(p); 25968d75effSDimitry Andric *reinterpret_cast<u8*>(s) = kAsanArrayCookieMagic; 26068d75effSDimitry Andric } 26168d75effSDimitry Andric 26268d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 26368d75effSDimitry Andric uptr __asan_load_cxx_array_cookie(uptr *p) { 26468d75effSDimitry Andric if (SANITIZER_WORDSIZE != 64) return *p; 26568d75effSDimitry Andric if (!flags()->poison_array_cookie) return *p; 26668d75effSDimitry Andric uptr s = MEM_TO_SHADOW(reinterpret_cast<uptr>(p)); 26768d75effSDimitry Andric u8 sval = *reinterpret_cast<u8*>(s); 26868d75effSDimitry Andric if (sval == kAsanArrayCookieMagic) return *p; 26968d75effSDimitry Andric // If sval is not kAsanArrayCookieMagic it can only be freed memory, 27068d75effSDimitry Andric // which means that we are going to get double-free. So, return 0 to avoid 27168d75effSDimitry Andric // infinite loop of destructors. We don't want to report a double-free here 27268d75effSDimitry Andric // though, so print a warning just in case. 27368d75effSDimitry Andric // CHECK_EQ(sval, kAsanHeapFreeMagic); 27468d75effSDimitry Andric if (sval == kAsanHeapFreeMagic) { 27568d75effSDimitry Andric Report("AddressSanitizer: loaded array cookie from free-d memory; " 27668d75effSDimitry Andric "expect a double-free report\n"); 27768d75effSDimitry Andric return 0; 27868d75effSDimitry Andric } 27968d75effSDimitry Andric // The cookie may remain unpoisoned if e.g. it comes from a custom 28068d75effSDimitry Andric // operator new defined inside a class. 28168d75effSDimitry Andric return *p; 28268d75effSDimitry Andric } 28368d75effSDimitry Andric 28468d75effSDimitry Andric // This is a simplified version of __asan_(un)poison_memory_region, which 28568d75effSDimitry Andric // assumes that left border of region to be poisoned is properly aligned. 28668d75effSDimitry Andric static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) { 28768d75effSDimitry Andric if (size == 0) return; 28868d75effSDimitry Andric uptr aligned_size = size & ~(SHADOW_GRANULARITY - 1); 28968d75effSDimitry Andric PoisonShadow(addr, aligned_size, 29068d75effSDimitry Andric do_poison ? kAsanStackUseAfterScopeMagic : 0); 29168d75effSDimitry Andric if (size == aligned_size) 29268d75effSDimitry Andric return; 29368d75effSDimitry Andric s8 end_offset = (s8)(size - aligned_size); 29468d75effSDimitry Andric s8* shadow_end = (s8*)MemToShadow(addr + aligned_size); 29568d75effSDimitry Andric s8 end_value = *shadow_end; 29668d75effSDimitry Andric if (do_poison) { 29768d75effSDimitry Andric // If possible, mark all the bytes mapping to last shadow byte as 29868d75effSDimitry Andric // unaddressable. 29968d75effSDimitry Andric if (end_value > 0 && end_value <= end_offset) 30068d75effSDimitry Andric *shadow_end = (s8)kAsanStackUseAfterScopeMagic; 30168d75effSDimitry Andric } else { 30268d75effSDimitry Andric // If necessary, mark few first bytes mapping to last shadow byte 30368d75effSDimitry Andric // as addressable 30468d75effSDimitry Andric if (end_value != 0) 30568d75effSDimitry Andric *shadow_end = Max(end_value, end_offset); 30668d75effSDimitry Andric } 30768d75effSDimitry Andric } 30868d75effSDimitry Andric 30968d75effSDimitry Andric void __asan_set_shadow_00(uptr addr, uptr size) { 31068d75effSDimitry Andric REAL(memset)((void *)addr, 0, size); 31168d75effSDimitry Andric } 31268d75effSDimitry Andric 31368d75effSDimitry Andric void __asan_set_shadow_f1(uptr addr, uptr size) { 31468d75effSDimitry Andric REAL(memset)((void *)addr, 0xf1, size); 31568d75effSDimitry Andric } 31668d75effSDimitry Andric 31768d75effSDimitry Andric void __asan_set_shadow_f2(uptr addr, uptr size) { 31868d75effSDimitry Andric REAL(memset)((void *)addr, 0xf2, size); 31968d75effSDimitry Andric } 32068d75effSDimitry Andric 32168d75effSDimitry Andric void __asan_set_shadow_f3(uptr addr, uptr size) { 32268d75effSDimitry Andric REAL(memset)((void *)addr, 0xf3, size); 32368d75effSDimitry Andric } 32468d75effSDimitry Andric 32568d75effSDimitry Andric void __asan_set_shadow_f5(uptr addr, uptr size) { 32668d75effSDimitry Andric REAL(memset)((void *)addr, 0xf5, size); 32768d75effSDimitry Andric } 32868d75effSDimitry Andric 32968d75effSDimitry Andric void __asan_set_shadow_f8(uptr addr, uptr size) { 33068d75effSDimitry Andric REAL(memset)((void *)addr, 0xf8, size); 33168d75effSDimitry Andric } 33268d75effSDimitry Andric 33368d75effSDimitry Andric void __asan_poison_stack_memory(uptr addr, uptr size) { 33468d75effSDimitry Andric VReport(1, "poisoning: %p %zx\n", (void *)addr, size); 33568d75effSDimitry Andric PoisonAlignedStackMemory(addr, size, true); 33668d75effSDimitry Andric } 33768d75effSDimitry Andric 33868d75effSDimitry Andric void __asan_unpoison_stack_memory(uptr addr, uptr size) { 33968d75effSDimitry Andric VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size); 34068d75effSDimitry Andric PoisonAlignedStackMemory(addr, size, false); 34168d75effSDimitry Andric } 34268d75effSDimitry Andric 34368d75effSDimitry Andric void __sanitizer_annotate_contiguous_container(const void *beg_p, 34468d75effSDimitry Andric const void *end_p, 34568d75effSDimitry Andric const void *old_mid_p, 34668d75effSDimitry Andric const void *new_mid_p) { 34768d75effSDimitry Andric if (!flags()->detect_container_overflow) return; 34868d75effSDimitry Andric VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, 34968d75effSDimitry Andric new_mid_p); 35068d75effSDimitry Andric uptr beg = reinterpret_cast<uptr>(beg_p); 35168d75effSDimitry Andric uptr end = reinterpret_cast<uptr>(end_p); 35268d75effSDimitry Andric uptr old_mid = reinterpret_cast<uptr>(old_mid_p); 35368d75effSDimitry Andric uptr new_mid = reinterpret_cast<uptr>(new_mid_p); 35468d75effSDimitry Andric uptr granularity = SHADOW_GRANULARITY; 35568d75effSDimitry Andric if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end && 35668d75effSDimitry Andric IsAligned(beg, granularity))) { 35768d75effSDimitry Andric GET_STACK_TRACE_FATAL_HERE; 35868d75effSDimitry Andric ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid, 35968d75effSDimitry Andric &stack); 36068d75effSDimitry Andric } 36168d75effSDimitry Andric CHECK_LE(end - beg, 362fe6060f1SDimitry Andric FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check. 36368d75effSDimitry Andric 36468d75effSDimitry Andric uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); 36568d75effSDimitry Andric uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); 36668d75effSDimitry Andric uptr d1 = RoundDownTo(old_mid, granularity); 36768d75effSDimitry Andric // uptr d2 = RoundUpTo(old_mid, granularity); 36868d75effSDimitry Andric // Currently we should be in this state: 36968d75effSDimitry Andric // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good. 37068d75effSDimitry Andric // Make a quick sanity check that we are indeed in this state. 37168d75effSDimitry Andric // 37268d75effSDimitry Andric // FIXME: Two of these three checks are disabled until we fix 37368d75effSDimitry Andric // https://github.com/google/sanitizers/issues/258. 37468d75effSDimitry Andric // if (d1 != d2) 37568d75effSDimitry Andric // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1); 37668d75effSDimitry Andric if (a + granularity <= d1) 37768d75effSDimitry Andric CHECK_EQ(*(u8*)MemToShadow(a), 0); 37868d75effSDimitry Andric // if (d2 + granularity <= c && c <= end) 37968d75effSDimitry Andric // CHECK_EQ(*(u8 *)MemToShadow(c - granularity), 38068d75effSDimitry Andric // kAsanContiguousContainerOOBMagic); 38168d75effSDimitry Andric 38268d75effSDimitry Andric uptr b1 = RoundDownTo(new_mid, granularity); 38368d75effSDimitry Andric uptr b2 = RoundUpTo(new_mid, granularity); 38468d75effSDimitry Andric // New state: 38568d75effSDimitry Andric // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good. 38668d75effSDimitry Andric PoisonShadow(a, b1 - a, 0); 38768d75effSDimitry Andric PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic); 38868d75effSDimitry Andric if (b1 != b2) { 38968d75effSDimitry Andric CHECK_EQ(b2 - b1, granularity); 39068d75effSDimitry Andric *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1); 39168d75effSDimitry Andric } 39268d75effSDimitry Andric } 39368d75effSDimitry Andric 39468d75effSDimitry Andric const void *__sanitizer_contiguous_container_find_bad_address( 39568d75effSDimitry Andric const void *beg_p, const void *mid_p, const void *end_p) { 39668d75effSDimitry Andric if (!flags()->detect_container_overflow) 39768d75effSDimitry Andric return nullptr; 39868d75effSDimitry Andric uptr beg = reinterpret_cast<uptr>(beg_p); 39968d75effSDimitry Andric uptr end = reinterpret_cast<uptr>(end_p); 40068d75effSDimitry Andric uptr mid = reinterpret_cast<uptr>(mid_p); 40168d75effSDimitry Andric CHECK_LE(beg, mid); 40268d75effSDimitry Andric CHECK_LE(mid, end); 40368d75effSDimitry Andric // Check some bytes starting from beg, some bytes around mid, and some bytes 40468d75effSDimitry Andric // ending with end. 40568d75effSDimitry Andric uptr kMaxRangeToCheck = 32; 40668d75effSDimitry Andric uptr r1_beg = beg; 40768d75effSDimitry Andric uptr r1_end = Min(beg + kMaxRangeToCheck, mid); 40868d75effSDimitry Andric uptr r2_beg = Max(beg, mid - kMaxRangeToCheck); 40968d75effSDimitry Andric uptr r2_end = Min(end, mid + kMaxRangeToCheck); 41068d75effSDimitry Andric uptr r3_beg = Max(end - kMaxRangeToCheck, mid); 41168d75effSDimitry Andric uptr r3_end = end; 41268d75effSDimitry Andric for (uptr i = r1_beg; i < r1_end; i++) 41368d75effSDimitry Andric if (AddressIsPoisoned(i)) 41468d75effSDimitry Andric return reinterpret_cast<const void *>(i); 41568d75effSDimitry Andric for (uptr i = r2_beg; i < mid; i++) 41668d75effSDimitry Andric if (AddressIsPoisoned(i)) 41768d75effSDimitry Andric return reinterpret_cast<const void *>(i); 41868d75effSDimitry Andric for (uptr i = mid; i < r2_end; i++) 41968d75effSDimitry Andric if (!AddressIsPoisoned(i)) 42068d75effSDimitry Andric return reinterpret_cast<const void *>(i); 42168d75effSDimitry Andric for (uptr i = r3_beg; i < r3_end; i++) 42268d75effSDimitry Andric if (!AddressIsPoisoned(i)) 42368d75effSDimitry Andric return reinterpret_cast<const void *>(i); 42468d75effSDimitry Andric return nullptr; 42568d75effSDimitry Andric } 42668d75effSDimitry Andric 42768d75effSDimitry Andric int __sanitizer_verify_contiguous_container(const void *beg_p, 42868d75effSDimitry Andric const void *mid_p, 42968d75effSDimitry Andric const void *end_p) { 43068d75effSDimitry Andric return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p, 43168d75effSDimitry Andric end_p) == nullptr; 43268d75effSDimitry Andric } 43368d75effSDimitry Andric 43468d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 43568d75effSDimitry Andric void __asan_poison_intra_object_redzone(uptr ptr, uptr size) { 43668d75effSDimitry Andric AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true); 43768d75effSDimitry Andric } 43868d75effSDimitry Andric 43968d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 44068d75effSDimitry Andric void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) { 44168d75effSDimitry Andric AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false); 44268d75effSDimitry Andric } 44368d75effSDimitry Andric 44468d75effSDimitry Andric // --- Implementation of LSan-specific functions --- {{{1 44568d75effSDimitry Andric namespace __lsan { 44668d75effSDimitry Andric bool WordIsPoisoned(uptr addr) { 44768d75effSDimitry Andric return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0); 44868d75effSDimitry Andric } 44968d75effSDimitry Andric } 450