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