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
20DECLARE_REAL(void *, memset, void *dest, int c, uptr n)
21DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n)
22DECLARE_REAL(void *, memmove, void *dest, const void *src, uptr n)
23
24namespace __msan {
25
26u32 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
33void 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
43void 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
98void 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
108void 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
117void CopyMemory(void *dst, const void *src, uptr size, StackTrace *stack) {
118  REAL(memcpy)(dst, src, size);
119  CopyShadowAndOrigin(dst, src, size, stack);
120}
121
122void 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
147void 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
165void 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