Home | History | Annotate | Download | only in msan
      1 //===-- msan_poisoning.cc ---------------------------------------*- C++ -*-===//
      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 MemorySanitizer.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "msan_poisoning.h"
     15 
     16 #include "interception/interception.h"
     17 #include "msan_origin.h"
     18 #include "sanitizer_common/sanitizer_common.h"
     19 
     20 DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
     21 DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
     22 DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n)
     23 
     24 namespace __msan {
     25 
     26 u32 GetOriginIfPoisoned(uptr addr, uptr size) {
     27   unsigned char *s = (unsigned char *)MEM_TO_SHADOW(addr);
     28   for (uptr i = 0; i < size; ++i)
     29     if (s[i]) return *(u32 *)SHADOW_TO_ORIGIN(((uptr)s + i) & ~3UL);
     30   return 0;
     31 }
     32 
     33 void SetOriginIfPoisoned(uptr addr, uptr src_shadow, uptr size,
     34                          u32 src_origin) {
     35   uptr dst_s = MEM_TO_SHADOW(addr);
     36   uptr src_s = src_shadow;
     37   uptr src_s_end = src_s + size;
     38 
     39   for (; src_s < src_s_end; ++dst_s, ++src_s)
     40     if (*(u8 *)src_s) *(u32 *)SHADOW_TO_ORIGIN(dst_s & ~3UL) = src_origin;
     41 }
     42 
     43 void CopyOrigin(const void *dst, const void *src, uptr size,
     44                 StackTrace *stack) {
     45   if (!MEM_IS_APP(dst) || !MEM_IS_APP(src)) return;
     46 
     47   uptr d = (uptr)dst;
     48   uptr beg = d & ~3UL;
     49   // Copy left unaligned origin if that memory is poisoned.
     50   if (beg < d) {
     51     u32 o = GetOriginIfPoisoned((uptr)src, d - beg);
     52     if (o) {
     53       if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
     54       *(u32 *)MEM_TO_ORIGIN(beg) = o;
     55     }
     56     beg += 4;
     57   }
     58 
     59   uptr end = (d + size) & ~3UL;
     60   // If both ends fall into the same 4-byte slot, we are done.
     61   if (end < beg) return;
     62 
     63   // Copy right unaligned origin if that memory is poisoned.
     64   if (end < d + size) {
     65     u32 o = GetOriginIfPoisoned((uptr)src + (end - d), (d + size) - end);
     66     if (o) {
     67       if (__msan_get_track_origins() > 1) o = ChainOrigin(o, stack);
     68       *(u32 *)MEM_TO_ORIGIN(end) = o;
     69     }
     70   }
     71 
     72   if (beg < end) {
     73     // Align src up.
     74     uptr s = ((uptr)src + 3) & ~3UL;
     75     // FIXME: factor out to msan_copy_origin_aligned
     76     if (__msan_get_track_origins() > 1) {
     77       u32 *src = (u32 *)MEM_TO_ORIGIN(s);
     78       u32 *src_s = (u32 *)MEM_TO_SHADOW(s);
     79       u32 *src_end = (u32 *)MEM_TO_ORIGIN(s + (end - beg));
     80       u32 *dst = (u32 *)MEM_TO_ORIGIN(beg);
     81       u32 src_o = 0;
     82       u32 dst_o = 0;
     83       for (; src < src_end; ++src, ++src_s, ++dst) {
     84         if (!*src_s) continue;
     85         if (*src != src_o) {
     86           src_o = *src;
     87           dst_o = ChainOrigin(src_o, stack);
     88         }
     89         *dst = dst_o;
     90       }
     91     } else {
     92       REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
     93                    end - beg);
     94     }
     95   }
     96 }
     97 
     98 void MoveShadowAndOrigin(const void *dst, const void *src, uptr size,
     99                          StackTrace *stack) {
    100   if (!MEM_IS_APP(dst)) return;
    101   if (!MEM_IS_APP(src)) return;
    102   if (src == dst) return;
    103   REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
    104                 (void *)MEM_TO_SHADOW((uptr)src), size);
    105   if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
    106 }
    107 
    108 void CopyShadowAndOrigin(const void *dst, const void *src, uptr size,
    109                          StackTrace *stack) {
    110   if (!MEM_IS_APP(dst)) return;
    111   if (!MEM_IS_APP(src)) return;
    112   REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
    113                (void *)MEM_TO_SHADOW((uptr)src), size);
    114   if (__msan_get_track_origins()) CopyOrigin(dst, src, size, stack);
    115 }
    116 
    117 void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {
    118   REAL(memcpy)(dst, src, size);
    119   CopyShadowAndOrigin(dst, src, size, stack);
    120 }
    121 
    122 void SetShadow(const void *ptr, uptr size, u8 value) {
    123   uptr PageSize = GetPageSizeCached();
    124   uptr shadow_beg = MEM_TO_SHADOW(ptr);
    125   uptr shadow_end = shadow_beg + size;
    126   if (value ||
    127       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
    128     REAL(memset)((void *)shadow_beg, value, shadow_end - shadow_beg);
    129   } else {
    130     uptr page_beg = RoundUpTo(shadow_beg, PageSize);
    131     uptr page_end = RoundDownTo(shadow_end, PageSize);
    132 
    133     if (page_beg >= page_end) {
    134       REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
    135     } else {
    136       if (page_beg != shadow_beg) {
    137         REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
    138       }
    139       if (page_end != shadow_end) {
    140         REAL(memset)((void *)page_end, 0, shadow_end - page_end);
    141       }
    142       MmapFixedNoReserve(page_beg, page_end - page_beg);
    143     }
    144   }
    145 }
    146 
    147 void SetOrigin(const void *dst, uptr size, u32 origin) {
    148   // Origin mapping is 4 bytes per 4 bytes of application memory.
    149   // Here we extend the range such that its left and right bounds are both
    150   // 4 byte aligned.
    151   uptr x = MEM_TO_ORIGIN((uptr)dst);
    152   uptr beg = x & ~3UL;               // align down.
    153   uptr end = (x + size + 3) & ~3UL;  // align up.
    154   u64 origin64 = ((u64)origin << 32) | origin;
    155   // This is like memset, but the value is 32-bit. We unroll by 2 to write
    156   // 64 bits at once. May want to unroll further to get 128-bit stores.
    157   if (beg & 7ULL) {
    158     *(u32 *)beg = origin;
    159     beg += 4;
    160   }
    161   for (uptr addr = beg; addr < (end & ~7UL); addr += 8) *(u64 *)addr = origin64;
    162   if (end & 7ULL) *(u32 *)(end - 4) = origin;
    163 }
    164 
    165 void PoisonMemory(const void *dst, uptr size, StackTrace *stack) {
    166   SetShadow(dst, size, (u8)-1);
    167 
    168   if (__msan_get_track_origins()) {
    169     Origin o = Origin::CreateHeapOrigin(stack);
    170     SetOrigin(dst, size, o.raw_id());
    171   }
    172 }
    173 
    174 }  // namespace __msan
    175