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