xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- dfsan.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 DataFlowSanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // DataFlowSanitizer runtime.  This file defines the public interface to
1268d75effSDimitry Andric // DataFlowSanitizer as well as the definition of certain runtime functions
1368d75effSDimitry Andric // called automatically by the compiler (specifically the instrumentation pass
1468d75effSDimitry Andric // in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
1568d75effSDimitry Andric //
1668d75effSDimitry Andric // The public interface is defined in include/sanitizer/dfsan_interface.h whose
1768d75effSDimitry Andric // functions are prefixed dfsan_ while the compiler interface functions are
1868d75effSDimitry Andric // prefixed __dfsan_.
1968d75effSDimitry Andric //===----------------------------------------------------------------------===//
2068d75effSDimitry Andric 
21e8d8bef9SDimitry Andric #include "dfsan/dfsan.h"
22e8d8bef9SDimitry Andric 
23fe6060f1SDimitry Andric #include "dfsan/dfsan_chained_origin_depot.h"
24fe6060f1SDimitry Andric #include "dfsan/dfsan_flags.h"
25fe6060f1SDimitry Andric #include "dfsan/dfsan_origin.h"
26fe6060f1SDimitry Andric #include "dfsan/dfsan_thread.h"
2768d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
2868d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
2968d75effSDimitry Andric #include "sanitizer_common/sanitizer_file.h"
3068d75effSDimitry Andric #include "sanitizer_common/sanitizer_flag_parser.h"
31e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
32e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
3368d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
34fe6060f1SDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h"
35e8d8bef9SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
36*0fca6ea1SDimitry Andric #if SANITIZER_LINUX
37*0fca6ea1SDimitry Andric #  include <sys/personality.h>
38*0fca6ea1SDimitry Andric #endif
3968d75effSDimitry Andric 
4068d75effSDimitry Andric using namespace __dfsan;
4168d75effSDimitry Andric 
4268d75effSDimitry Andric Flags __dfsan::flags_data;
4368d75effSDimitry Andric 
44e8d8bef9SDimitry Andric // The size of TLS variables. These constants must be kept in sync with the ones
45e8d8bef9SDimitry Andric // in DataFlowSanitizer.cpp.
46e8d8bef9SDimitry Andric static const int kDFsanArgTlsSize = 800;
47e8d8bef9SDimitry Andric static const int kDFsanRetvalTlsSize = 800;
48fe6060f1SDimitry Andric static const int kDFsanArgOriginTlsSize = 800;
49e8d8bef9SDimitry Andric 
50e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64
51e8d8bef9SDimitry Andric     __dfsan_retval_tls[kDFsanRetvalTlsSize / sizeof(u64)];
52fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __dfsan_retval_origin_tls;
53e8d8bef9SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64
54e8d8bef9SDimitry Andric     __dfsan_arg_tls[kDFsanArgTlsSize / sizeof(u64)];
55fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32
56fe6060f1SDimitry Andric     __dfsan_arg_origin_tls[kDFsanArgOriginTlsSize / sizeof(u32)];
5768d75effSDimitry Andric 
58fe6060f1SDimitry Andric // Instrumented code may set this value in terms of -dfsan-track-origins.
59fe6060f1SDimitry Andric // * undefined or 0: do not track origins.
60fe6060f1SDimitry Andric // * 1: track origins at memory store operations.
61fe6060f1SDimitry Andric // * 2: track origins at memory load and store operations.
62fe6060f1SDimitry Andric //      TODO: track callsites.
63fe6060f1SDimitry Andric extern "C" SANITIZER_WEAK_ATTRIBUTE const int __dfsan_track_origins;
64fe6060f1SDimitry Andric 
65fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int dfsan_get_track_origins() {
66fe6060f1SDimitry Andric   return &__dfsan_track_origins ? __dfsan_track_origins : 0;
67fe6060f1SDimitry Andric }
6868d75effSDimitry Andric 
6968d75effSDimitry Andric // On Linux/x86_64, memory is laid out as follows:
7068d75effSDimitry Andric //
7168d75effSDimitry Andric //  +--------------------+ 0x800000000000 (top of memory)
72fe6060f1SDimitry Andric //  |    application 3   |
73fe6060f1SDimitry Andric //  +--------------------+ 0x700000000000
74fe6060f1SDimitry Andric //  |      invalid       |
75fe6060f1SDimitry Andric //  +--------------------+ 0x610000000000
76fe6060f1SDimitry Andric //  |      origin 1      |
77fe6060f1SDimitry Andric //  +--------------------+ 0x600000000000
78fe6060f1SDimitry Andric //  |    application 2   |
79fe6060f1SDimitry Andric //  +--------------------+ 0x510000000000
80fe6060f1SDimitry Andric //  |      shadow 1      |
81fe6060f1SDimitry Andric //  +--------------------+ 0x500000000000
82fe6060f1SDimitry Andric //  |      invalid       |
83fe6060f1SDimitry Andric //  +--------------------+ 0x400000000000
84fe6060f1SDimitry Andric //  |      origin 3      |
85fe6060f1SDimitry Andric //  +--------------------+ 0x300000000000
86fe6060f1SDimitry Andric //  |      shadow 3      |
87fe6060f1SDimitry Andric //  +--------------------+ 0x200000000000
88fe6060f1SDimitry Andric //  |      origin 2      |
89fe6060f1SDimitry Andric //  +--------------------+ 0x110000000000
90fe6060f1SDimitry Andric //  |      invalid       |
91fe6060f1SDimitry Andric //  +--------------------+ 0x100000000000
92fe6060f1SDimitry Andric //  |      shadow 2      |
93fe6060f1SDimitry Andric //  +--------------------+ 0x010000000000
94fe6060f1SDimitry Andric //  |    application 1   |
9568d75effSDimitry Andric //  +--------------------+ 0x000000000000
9668d75effSDimitry Andric //
97fe6060f1SDimitry Andric //  MEM_TO_SHADOW(mem) = mem ^ 0x500000000000
98fe6060f1SDimitry Andric //  SHADOW_TO_ORIGIN(shadow) = shadow + 0x100000000000
9968d75effSDimitry Andric 
10068d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
10168d75effSDimitry Andric dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {
10268d75effSDimitry Andric   dfsan_label label = ls[0];
103e8d8bef9SDimitry Andric   for (uptr i = 1; i != n; ++i)
104e8d8bef9SDimitry Andric     label |= ls[i];
105e8d8bef9SDimitry Andric   return label;
106e8d8bef9SDimitry Andric }
107e8d8bef9SDimitry Andric 
108fe6060f1SDimitry Andric // Return the union of all the n labels from addr at the high 32 bit, and the
109fe6060f1SDimitry Andric // origin of the first taint byte at the low 32 bit.
110fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64
111fe6060f1SDimitry Andric __dfsan_load_label_and_origin(const void *addr, uptr n) {
112fe6060f1SDimitry Andric   dfsan_label label = 0;
113fe6060f1SDimitry Andric   u64 ret = 0;
114fe6060f1SDimitry Andric   uptr p = (uptr)addr;
115fe6060f1SDimitry Andric   dfsan_label *s = shadow_for((void *)p);
116fe6060f1SDimitry Andric   for (uptr i = 0; i < n; ++i) {
117fe6060f1SDimitry Andric     dfsan_label l = s[i];
118fe6060f1SDimitry Andric     if (!l)
119fe6060f1SDimitry Andric       continue;
120fe6060f1SDimitry Andric     label |= l;
121fe6060f1SDimitry Andric     if (!ret)
122fe6060f1SDimitry Andric       ret = *(dfsan_origin *)origin_for((void *)(p + i));
123fe6060f1SDimitry Andric   }
124fe6060f1SDimitry Andric   return ret | (u64)label << 32;
125fe6060f1SDimitry Andric }
126fe6060f1SDimitry Andric 
127e8d8bef9SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE
12868d75effSDimitry Andric void __dfsan_unimplemented(char *fname) {
12968d75effSDimitry Andric   if (flags().warn_unimplemented)
13068d75effSDimitry Andric     Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",
13168d75effSDimitry Andric            fname);
13268d75effSDimitry Andric }
13368d75effSDimitry Andric 
13481ad6265SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_wrapper_extern_weak_null(
13581ad6265SDimitry Andric     const void *addr, char *fname) {
13681ad6265SDimitry Andric   if (!addr)
13781ad6265SDimitry Andric     Report(
13881ad6265SDimitry Andric         "ERROR: DataFlowSanitizer: dfsan generated wrapper calling null "
13981ad6265SDimitry Andric         "extern_weak function %s\nIf this only happens with dfsan, the "
14081ad6265SDimitry Andric         "dfsan instrumentation pass may be accidentally optimizing out a "
14181ad6265SDimitry Andric         "null check\n",
14281ad6265SDimitry Andric         fname);
14381ad6265SDimitry Andric }
14481ad6265SDimitry Andric 
14568d75effSDimitry Andric // Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function
14668d75effSDimitry Andric // to try to figure out where labels are being introduced in a nominally
14768d75effSDimitry Andric // label-free program.
14868d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
14968d75effSDimitry Andric   if (flags().warn_nonzero_labels)
15068d75effSDimitry Andric     Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
15168d75effSDimitry Andric }
15268d75effSDimitry Andric 
15368d75effSDimitry Andric // Indirect call to an uninstrumented vararg function. We don't have a way of
15468d75effSDimitry Andric // handling these at the moment.
15568d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
15668d75effSDimitry Andric __dfsan_vararg_wrapper(const char *fname) {
15768d75effSDimitry Andric   Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
15868d75effSDimitry Andric          "function %s\n", fname);
15968d75effSDimitry Andric   Die();
16068d75effSDimitry Andric }
16168d75effSDimitry Andric 
162fe6060f1SDimitry Andric // Resolves the union of two labels.
16368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
16468d75effSDimitry Andric dfsan_union(dfsan_label l1, dfsan_label l2) {
165fe6060f1SDimitry Andric   return l1 | l2;
16668d75effSDimitry Andric }
16768d75effSDimitry Andric 
168fe6060f1SDimitry Andric static const uptr kOriginAlign = sizeof(dfsan_origin);
169fe6060f1SDimitry Andric static const uptr kOriginAlignMask = ~(kOriginAlign - 1UL);
170fe6060f1SDimitry Andric 
171fe6060f1SDimitry Andric static uptr OriginAlignUp(uptr u) {
172fe6060f1SDimitry Andric   return (u + kOriginAlign - 1) & kOriginAlignMask;
17368d75effSDimitry Andric }
17468d75effSDimitry Andric 
175fe6060f1SDimitry Andric static uptr OriginAlignDown(uptr u) { return u & kOriginAlignMask; }
176fe6060f1SDimitry Andric 
177fe6060f1SDimitry Andric // Return the origin of the first taint byte in the size bytes from the address
178fe6060f1SDimitry Andric // addr.
179fe6060f1SDimitry Andric static dfsan_origin GetOriginIfTainted(uptr addr, uptr size) {
180fe6060f1SDimitry Andric   for (uptr i = 0; i < size; ++i, ++addr) {
181fe6060f1SDimitry Andric     dfsan_label *s = shadow_for((void *)addr);
182fe6060f1SDimitry Andric 
183fe6060f1SDimitry Andric     if (*s) {
184fe6060f1SDimitry Andric       // Validate address region.
185fe6060f1SDimitry Andric       CHECK(MEM_IS_SHADOW(s));
186fe6060f1SDimitry Andric       return *(dfsan_origin *)origin_for((void *)addr);
187fe6060f1SDimitry Andric     }
188fe6060f1SDimitry Andric   }
189fe6060f1SDimitry Andric   return 0;
190fe6060f1SDimitry Andric }
191fe6060f1SDimitry Andric 
192fe6060f1SDimitry Andric // For platforms which support slow unwinder only, we need to restrict the store
193fe6060f1SDimitry Andric // context size to 1, basically only storing the current pc, because the slow
194fe6060f1SDimitry Andric // unwinder which is based on libunwind is not async signal safe and causes
195fe6060f1SDimitry Andric // random freezes in forking applications as well as in signal handlers.
196fe6060f1SDimitry Andric // DFSan supports only Linux. So we do not restrict the store context size.
197fe6060f1SDimitry Andric #define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
198fe6060f1SDimitry Andric   BufferedStackTrace stack;                 \
199fe6060f1SDimitry Andric   stack.Unwind(pc, bp, nullptr, true, flags().store_context_size);
200fe6060f1SDimitry Andric 
201fe6060f1SDimitry Andric #define PRINT_CALLER_STACK_TRACE        \
202fe6060f1SDimitry Andric   {                                     \
20306c3fb27SDimitry Andric     GET_CALLER_PC_BP;                   \
204fe6060f1SDimitry Andric     GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
205fe6060f1SDimitry Andric     stack.Print();                      \
206fe6060f1SDimitry Andric   }
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric // Return a chain with the previous ID id and the current stack.
209fe6060f1SDimitry Andric // from_init = true if this is the first chain of an origin tracking path.
210fe6060f1SDimitry Andric static u32 ChainOrigin(u32 id, StackTrace *stack, bool from_init = false) {
211fe6060f1SDimitry Andric   // StackDepot is not async signal safe. Do not create new chains in a signal
212fe6060f1SDimitry Andric   // handler.
213fe6060f1SDimitry Andric   DFsanThread *t = GetCurrentThread();
214fe6060f1SDimitry Andric   if (t && t->InSignalHandler())
215fe6060f1SDimitry Andric     return id;
216fe6060f1SDimitry Andric 
217fe6060f1SDimitry Andric   // As an optimization the origin of an application byte is updated only when
218fe6060f1SDimitry Andric   // its shadow is non-zero. Because we are only interested in the origins of
219fe6060f1SDimitry Andric   // taint labels, it does not matter what origin a zero label has. This reduces
220fe6060f1SDimitry Andric   // memory write cost. MSan does similar optimization. The following invariant
221fe6060f1SDimitry Andric   // may not hold because of some bugs. We check the invariant to help debug.
222fe6060f1SDimitry Andric   if (!from_init && id == 0 && flags().check_origin_invariant) {
223fe6060f1SDimitry Andric     Printf("  DFSan found invalid origin invariant\n");
224fe6060f1SDimitry Andric     PRINT_CALLER_STACK_TRACE
225fe6060f1SDimitry Andric   }
226fe6060f1SDimitry Andric 
227fe6060f1SDimitry Andric   Origin o = Origin::FromRawId(id);
228fe6060f1SDimitry Andric   stack->tag = StackTrace::TAG_UNKNOWN;
229fe6060f1SDimitry Andric   Origin chained = Origin::CreateChainedOrigin(o, stack);
230fe6060f1SDimitry Andric   return chained.raw_id();
231fe6060f1SDimitry Andric }
232fe6060f1SDimitry Andric 
233fe6060f1SDimitry Andric static void ChainAndWriteOriginIfTainted(uptr src, uptr size, uptr dst,
234fe6060f1SDimitry Andric                                          StackTrace *stack) {
235fe6060f1SDimitry Andric   dfsan_origin o = GetOriginIfTainted(src, size);
236fe6060f1SDimitry Andric   if (o) {
237fe6060f1SDimitry Andric     o = ChainOrigin(o, stack);
238fe6060f1SDimitry Andric     *(dfsan_origin *)origin_for((void *)dst) = o;
239fe6060f1SDimitry Andric   }
240fe6060f1SDimitry Andric }
241fe6060f1SDimitry Andric 
242fe6060f1SDimitry Andric // Copy the origins of the size bytes from src to dst. The source and target
243fe6060f1SDimitry Andric // memory ranges cannot be overlapped. This is used by memcpy. stack records the
244fe6060f1SDimitry Andric // stack trace of the memcpy. When dst and src are not 4-byte aligned properly,
245fe6060f1SDimitry Andric // origins at the unaligned address boundaries may be overwritten because four
246fe6060f1SDimitry Andric // contiguous bytes share the same origin.
247fe6060f1SDimitry Andric static void CopyOrigin(const void *dst, const void *src, uptr size,
248fe6060f1SDimitry Andric                        StackTrace *stack) {
249fe6060f1SDimitry Andric   uptr d = (uptr)dst;
250fe6060f1SDimitry Andric   uptr beg = OriginAlignDown(d);
251fe6060f1SDimitry Andric   // Copy left unaligned origin if that memory is tainted.
252fe6060f1SDimitry Andric   if (beg < d) {
253fe6060f1SDimitry Andric     ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);
254fe6060f1SDimitry Andric     beg += kOriginAlign;
255fe6060f1SDimitry Andric   }
256fe6060f1SDimitry Andric 
257fe6060f1SDimitry Andric   uptr end = OriginAlignDown(d + size);
258fe6060f1SDimitry Andric   // If both ends fall into the same 4-byte slot, we are done.
259fe6060f1SDimitry Andric   if (end < beg)
260fe6060f1SDimitry Andric     return;
261fe6060f1SDimitry Andric 
262fe6060f1SDimitry Andric   // Copy right unaligned origin if that memory is tainted.
263fe6060f1SDimitry Andric   if (end < d + size)
264fe6060f1SDimitry Andric     ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,
265fe6060f1SDimitry Andric                                  stack);
266fe6060f1SDimitry Andric 
267fe6060f1SDimitry Andric   if (beg >= end)
268fe6060f1SDimitry Andric     return;
269fe6060f1SDimitry Andric 
270fe6060f1SDimitry Andric   // Align src up.
271fe6060f1SDimitry Andric   uptr src_a = OriginAlignUp((uptr)src);
272fe6060f1SDimitry Andric   dfsan_origin *src_o = origin_for((void *)src_a);
273fe6060f1SDimitry Andric   u32 *src_s = (u32 *)shadow_for((void *)src_a);
274fe6060f1SDimitry Andric   dfsan_origin *src_end = origin_for((void *)(src_a + (end - beg)));
275fe6060f1SDimitry Andric   dfsan_origin *dst_o = origin_for((void *)beg);
276fe6060f1SDimitry Andric   dfsan_origin last_src_o = 0;
277fe6060f1SDimitry Andric   dfsan_origin last_dst_o = 0;
278fe6060f1SDimitry Andric   for (; src_o < src_end; ++src_o, ++src_s, ++dst_o) {
279fe6060f1SDimitry Andric     if (!*src_s)
280fe6060f1SDimitry Andric       continue;
281fe6060f1SDimitry Andric     if (*src_o != last_src_o) {
282fe6060f1SDimitry Andric       last_src_o = *src_o;
283fe6060f1SDimitry Andric       last_dst_o = ChainOrigin(last_src_o, stack);
284fe6060f1SDimitry Andric     }
285fe6060f1SDimitry Andric     *dst_o = last_dst_o;
286fe6060f1SDimitry Andric   }
287fe6060f1SDimitry Andric }
288fe6060f1SDimitry Andric 
289fe6060f1SDimitry Andric // Copy the origins of the size bytes from src to dst. The source and target
290fe6060f1SDimitry Andric // memory ranges may be overlapped. So the copy is done in a reverse order.
291fe6060f1SDimitry Andric // This is used by memmove. stack records the stack trace of the memmove.
292fe6060f1SDimitry Andric static void ReverseCopyOrigin(const void *dst, const void *src, uptr size,
293fe6060f1SDimitry Andric                               StackTrace *stack) {
294fe6060f1SDimitry Andric   uptr d = (uptr)dst;
295fe6060f1SDimitry Andric   uptr end = OriginAlignDown(d + size);
296fe6060f1SDimitry Andric 
297fe6060f1SDimitry Andric   // Copy right unaligned origin if that memory is tainted.
298fe6060f1SDimitry Andric   if (end < d + size)
299fe6060f1SDimitry Andric     ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,
300fe6060f1SDimitry Andric                                  stack);
301fe6060f1SDimitry Andric 
302fe6060f1SDimitry Andric   uptr beg = OriginAlignDown(d);
303fe6060f1SDimitry Andric 
304fe6060f1SDimitry Andric   if (beg + kOriginAlign < end) {
305fe6060f1SDimitry Andric     // Align src up.
306fe6060f1SDimitry Andric     uptr src_a = OriginAlignUp((uptr)src);
307fe6060f1SDimitry Andric     void *src_end = (void *)(src_a + end - beg - kOriginAlign);
308fe6060f1SDimitry Andric     dfsan_origin *src_end_o = origin_for(src_end);
309fe6060f1SDimitry Andric     u32 *src_end_s = (u32 *)shadow_for(src_end);
310fe6060f1SDimitry Andric     dfsan_origin *src_begin_o = origin_for((void *)src_a);
311fe6060f1SDimitry Andric     dfsan_origin *dst = origin_for((void *)(end - kOriginAlign));
312fe6060f1SDimitry Andric     dfsan_origin last_src_o = 0;
313fe6060f1SDimitry Andric     dfsan_origin last_dst_o = 0;
314fe6060f1SDimitry Andric     for (; src_end_o >= src_begin_o; --src_end_o, --src_end_s, --dst) {
315fe6060f1SDimitry Andric       if (!*src_end_s)
316fe6060f1SDimitry Andric         continue;
317fe6060f1SDimitry Andric       if (*src_end_o != last_src_o) {
318fe6060f1SDimitry Andric         last_src_o = *src_end_o;
319fe6060f1SDimitry Andric         last_dst_o = ChainOrigin(last_src_o, stack);
320fe6060f1SDimitry Andric       }
321fe6060f1SDimitry Andric       *dst = last_dst_o;
322fe6060f1SDimitry Andric     }
323fe6060f1SDimitry Andric   }
324fe6060f1SDimitry Andric 
325fe6060f1SDimitry Andric   // Copy left unaligned origin if that memory is tainted.
326fe6060f1SDimitry Andric   if (beg < d)
327fe6060f1SDimitry Andric     ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);
328fe6060f1SDimitry Andric }
329fe6060f1SDimitry Andric 
330fe6060f1SDimitry Andric // Copy or move the origins of the len bytes from src to dst. The source and
331fe6060f1SDimitry Andric // target memory ranges may or may not be overlapped. This is used by memory
332fe6060f1SDimitry Andric // transfer operations. stack records the stack trace of the memory transfer
333fe6060f1SDimitry Andric // operation.
334fe6060f1SDimitry Andric static void MoveOrigin(const void *dst, const void *src, uptr size,
335fe6060f1SDimitry Andric                        StackTrace *stack) {
336fe6060f1SDimitry Andric   // Validate address regions.
337fe6060f1SDimitry Andric   if (!MEM_IS_SHADOW(shadow_for(dst)) ||
338fe6060f1SDimitry Andric       !MEM_IS_SHADOW(shadow_for((void *)((uptr)dst + size))) ||
339fe6060f1SDimitry Andric       !MEM_IS_SHADOW(shadow_for(src)) ||
340fe6060f1SDimitry Andric       !MEM_IS_SHADOW(shadow_for((void *)((uptr)src + size)))) {
341fe6060f1SDimitry Andric     CHECK(false);
342fe6060f1SDimitry Andric     return;
343fe6060f1SDimitry Andric   }
344fe6060f1SDimitry Andric   // If destination origin range overlaps with source origin range, move
345fe6060f1SDimitry Andric   // origins by copying origins in a reverse order; otherwise, copy origins in
346fe6060f1SDimitry Andric   // a normal order. The orders of origin transfer are consistent with the
347fe6060f1SDimitry Andric   // orders of how memcpy and memmove transfer user data.
34804eeddc0SDimitry Andric   uptr src_aligned_beg = OriginAlignDown((uptr)src);
34904eeddc0SDimitry Andric   uptr src_aligned_end = OriginAlignDown((uptr)src + size);
35004eeddc0SDimitry Andric   uptr dst_aligned_beg = OriginAlignDown((uptr)dst);
351fe6060f1SDimitry Andric   if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)
352fe6060f1SDimitry Andric     return ReverseCopyOrigin(dst, src, size, stack);
353fe6060f1SDimitry Andric   return CopyOrigin(dst, src, size, stack);
354fe6060f1SDimitry Andric }
355fe6060f1SDimitry Andric 
356fe6060f1SDimitry Andric // Set the size bytes from the addres dst to be the origin value.
357fe6060f1SDimitry Andric static void SetOrigin(const void *dst, uptr size, u32 origin) {
358fe6060f1SDimitry Andric   if (size == 0)
359fe6060f1SDimitry Andric     return;
360fe6060f1SDimitry Andric 
361fe6060f1SDimitry Andric   // Origin mapping is 4 bytes per 4 bytes of application memory.
362fe6060f1SDimitry Andric   // Here we extend the range such that its left and right bounds are both
363fe6060f1SDimitry Andric   // 4 byte aligned.
364fe6060f1SDimitry Andric   uptr x = unaligned_origin_for((uptr)dst);
365fe6060f1SDimitry Andric   uptr beg = OriginAlignDown(x);
366fe6060f1SDimitry Andric   uptr end = OriginAlignUp(x + size);  // align up.
367fe6060f1SDimitry Andric   u64 origin64 = ((u64)origin << 32) | origin;
368fe6060f1SDimitry Andric   // This is like memset, but the value is 32-bit. We unroll by 2 to write
369fe6060f1SDimitry Andric   // 64 bits at once. May want to unroll further to get 128-bit stores.
370fe6060f1SDimitry Andric   if (beg & 7ULL) {
371fe6060f1SDimitry Andric     if (*(u32 *)beg != origin)
372fe6060f1SDimitry Andric       *(u32 *)beg = origin;
373fe6060f1SDimitry Andric     beg += 4;
374fe6060f1SDimitry Andric   }
375fe6060f1SDimitry Andric   for (uptr addr = beg; addr < (end & ~7UL); addr += 8) {
376fe6060f1SDimitry Andric     if (*(u64 *)addr == origin64)
377fe6060f1SDimitry Andric       continue;
378fe6060f1SDimitry Andric     *(u64 *)addr = origin64;
379fe6060f1SDimitry Andric   }
380fe6060f1SDimitry Andric   if (end & 7ULL)
381fe6060f1SDimitry Andric     if (*(u32 *)(end - kOriginAlign) != origin)
382fe6060f1SDimitry Andric       *(u32 *)(end - kOriginAlign) = origin;
383fe6060f1SDimitry Andric }
384fe6060f1SDimitry Andric 
385fe6060f1SDimitry Andric #define RET_CHAIN_ORIGIN(id)           \
38606c3fb27SDimitry Andric   GET_CALLER_PC_BP;                    \
387fe6060f1SDimitry Andric   GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
388fe6060f1SDimitry Andric   return ChainOrigin(id, &stack);
389fe6060f1SDimitry Andric 
390fe6060f1SDimitry Andric // Return a new origin chain with the previous ID id and the current stack
391fe6060f1SDimitry Andric // trace.
392fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
393fe6060f1SDimitry Andric __dfsan_chain_origin(dfsan_origin id) {
394fe6060f1SDimitry Andric   RET_CHAIN_ORIGIN(id)
395fe6060f1SDimitry Andric }
396fe6060f1SDimitry Andric 
397fe6060f1SDimitry Andric // Return a new origin chain with the previous ID id and the current stack
398fe6060f1SDimitry Andric // trace if the label is tainted.
399fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
400fe6060f1SDimitry Andric __dfsan_chain_origin_if_tainted(dfsan_label label, dfsan_origin id) {
401fe6060f1SDimitry Andric   if (!label)
402fe6060f1SDimitry Andric     return id;
403fe6060f1SDimitry Andric   RET_CHAIN_ORIGIN(id)
404fe6060f1SDimitry Andric }
405fe6060f1SDimitry Andric 
406fe6060f1SDimitry Andric // Copy or move the origins of the len bytes from src to dst.
407fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_mem_origin_transfer(
408fe6060f1SDimitry Andric     const void *dst, const void *src, uptr len) {
409fe6060f1SDimitry Andric   if (src == dst)
410e8d8bef9SDimitry Andric     return;
411fe6060f1SDimitry Andric   GET_CALLER_PC_BP;
412fe6060f1SDimitry Andric   GET_STORE_STACK_TRACE_PC_BP(pc, bp);
413fe6060f1SDimitry Andric   MoveOrigin(dst, src, len, &stack);
414e8d8bef9SDimitry Andric }
415e8d8bef9SDimitry Andric 
41604eeddc0SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_origin_transfer(
41704eeddc0SDimitry Andric     const void *dst, const void *src, uptr len) {
418fe6060f1SDimitry Andric   __dfsan_mem_origin_transfer(dst, src, len);
419fe6060f1SDimitry Andric }
420fe6060f1SDimitry Andric 
421bdd1243dSDimitry Andric static void CopyShadow(void *dst, const void *src, uptr len) {
42204eeddc0SDimitry Andric   internal_memcpy((void *)__dfsan::shadow_for(dst),
42304eeddc0SDimitry Andric                   (const void *)__dfsan::shadow_for(src),
42404eeddc0SDimitry Andric                   len * sizeof(dfsan_label));
42504eeddc0SDimitry Andric }
42604eeddc0SDimitry Andric 
427bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_shadow_transfer(
428bdd1243dSDimitry Andric     void *dst, const void *src, uptr len) {
429bdd1243dSDimitry Andric   CopyShadow(dst, src, len);
430bdd1243dSDimitry Andric }
431bdd1243dSDimitry Andric 
432bdd1243dSDimitry Andric // Copy shadow and origins of the len bytes from src to dst.
433bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
434bdd1243dSDimitry Andric __dfsan_mem_shadow_origin_transfer(void *dst, const void *src, uptr size) {
435bdd1243dSDimitry Andric   if (src == dst)
436bdd1243dSDimitry Andric     return;
437bdd1243dSDimitry Andric   CopyShadow(dst, src, size);
438bdd1243dSDimitry Andric   if (dfsan_get_track_origins()) {
439bdd1243dSDimitry Andric     // Duplicating code instead of calling __dfsan_mem_origin_transfer
440bdd1243dSDimitry Andric     // so that the getting the caller stack frame works correctly.
441bdd1243dSDimitry Andric     GET_CALLER_PC_BP;
442bdd1243dSDimitry Andric     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
443bdd1243dSDimitry Andric     MoveOrigin(dst, src, size, &stack);
444bdd1243dSDimitry Andric   }
445bdd1243dSDimitry Andric }
446bdd1243dSDimitry Andric 
447bdd1243dSDimitry Andric // Copy shadow and origins as per __atomic_compare_exchange.
448bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
449bdd1243dSDimitry Andric __dfsan_mem_shadow_origin_conditional_exchange(u8 condition, void *target,
450bdd1243dSDimitry Andric                                                void *expected,
451bdd1243dSDimitry Andric                                                const void *desired, uptr size) {
452bdd1243dSDimitry Andric   void *dst;
453bdd1243dSDimitry Andric   const void *src;
454bdd1243dSDimitry Andric   // condition is result of native call to __atomic_compare_exchange
455bdd1243dSDimitry Andric   if (condition) {
456bdd1243dSDimitry Andric     // Copy desired into target
457bdd1243dSDimitry Andric     dst = target;
458bdd1243dSDimitry Andric     src = desired;
459bdd1243dSDimitry Andric   } else {
460bdd1243dSDimitry Andric     // Copy target into expected
461bdd1243dSDimitry Andric     dst = expected;
462bdd1243dSDimitry Andric     src = target;
463bdd1243dSDimitry Andric   }
464bdd1243dSDimitry Andric   if (src == dst)
465bdd1243dSDimitry Andric     return;
466bdd1243dSDimitry Andric   CopyShadow(dst, src, size);
467bdd1243dSDimitry Andric   if (dfsan_get_track_origins()) {
468bdd1243dSDimitry Andric     // Duplicating code instead of calling __dfsan_mem_origin_transfer
469bdd1243dSDimitry Andric     // so that the getting the caller stack frame works correctly.
470bdd1243dSDimitry Andric     GET_CALLER_PC_BP;
471bdd1243dSDimitry Andric     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
472bdd1243dSDimitry Andric     MoveOrigin(dst, src, size, &stack);
473bdd1243dSDimitry Andric   }
474bdd1243dSDimitry Andric }
475bdd1243dSDimitry Andric 
476fe6060f1SDimitry Andric namespace __dfsan {
477fe6060f1SDimitry Andric 
478fe6060f1SDimitry Andric bool dfsan_inited = false;
479fe6060f1SDimitry Andric bool dfsan_init_is_running = false;
480fe6060f1SDimitry Andric 
481fe6060f1SDimitry Andric void dfsan_copy_memory(void *dst, const void *src, uptr size) {
482fe6060f1SDimitry Andric   internal_memcpy(dst, src, size);
48304eeddc0SDimitry Andric   dfsan_mem_shadow_transfer(dst, src, size);
484fe6060f1SDimitry Andric   if (dfsan_get_track_origins())
485fe6060f1SDimitry Andric     dfsan_mem_origin_transfer(dst, src, size);
486fe6060f1SDimitry Andric }
487fe6060f1SDimitry Andric 
488fe6060f1SDimitry Andric // Releases the pages within the origin address range.
489fe6060f1SDimitry Andric static void ReleaseOrigins(void *addr, uptr size) {
490fe6060f1SDimitry Andric   const uptr beg_origin_addr = (uptr)__dfsan::origin_for(addr);
491fe6060f1SDimitry Andric   const void *end_addr = (void *)((uptr)addr + size);
492fe6060f1SDimitry Andric   const uptr end_origin_addr = (uptr)__dfsan::origin_for(end_addr);
493fe6060f1SDimitry Andric 
494fe6060f1SDimitry Andric   if (end_origin_addr - beg_origin_addr <
495fe6060f1SDimitry Andric       common_flags()->clear_shadow_mmap_threshold)
496fe6060f1SDimitry Andric     return;
497fe6060f1SDimitry Andric 
498fe6060f1SDimitry Andric   const uptr page_size = GetPageSizeCached();
499fe6060f1SDimitry Andric   const uptr beg_aligned = RoundUpTo(beg_origin_addr, page_size);
500fe6060f1SDimitry Andric   const uptr end_aligned = RoundDownTo(end_origin_addr, page_size);
501fe6060f1SDimitry Andric 
502fe6060f1SDimitry Andric   if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
503fe6060f1SDimitry Andric     Die();
504fe6060f1SDimitry Andric }
505fe6060f1SDimitry Andric 
506349cc55cSDimitry Andric static void WriteZeroShadowInRange(uptr beg, uptr end) {
507349cc55cSDimitry Andric   // Don't write the label if it is already the value we need it to be.
508349cc55cSDimitry Andric   // In a program where most addresses are not labeled, it is common that
509349cc55cSDimitry Andric   // a page of shadow memory is entirely zeroed.  The Linux copy-on-write
510349cc55cSDimitry Andric   // implementation will share all of the zeroed pages, making a copy of a
511349cc55cSDimitry Andric   // page when any value is written.  The un-sharing will happen even if
512349cc55cSDimitry Andric   // the value written does not change the value in memory.  Avoiding the
513349cc55cSDimitry Andric   // write when both |label| and |*labelp| are zero dramatically reduces
514349cc55cSDimitry Andric   // the amount of real memory used by large programs.
515349cc55cSDimitry Andric   if (!mem_is_zero((const char *)beg, end - beg))
516349cc55cSDimitry Andric     internal_memset((void *)beg, 0, end - beg);
517349cc55cSDimitry Andric }
518349cc55cSDimitry Andric 
519fe6060f1SDimitry Andric // Releases the pages within the shadow address range, and sets
520e8d8bef9SDimitry Andric // the shadow addresses not on the pages to be 0.
521fe6060f1SDimitry Andric static void ReleaseOrClearShadows(void *addr, uptr size) {
522fe6060f1SDimitry Andric   const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
523e8d8bef9SDimitry Andric   const void *end_addr = (void *)((uptr)addr + size);
524e8d8bef9SDimitry Andric   const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr);
525fe6060f1SDimitry Andric 
526fe6060f1SDimitry Andric   if (end_shadow_addr - beg_shadow_addr <
527349cc55cSDimitry Andric       common_flags()->clear_shadow_mmap_threshold) {
528349cc55cSDimitry Andric     WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
529349cc55cSDimitry Andric     return;
530349cc55cSDimitry Andric   }
531fe6060f1SDimitry Andric 
532e8d8bef9SDimitry Andric   const uptr page_size = GetPageSizeCached();
533e8d8bef9SDimitry Andric   const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size);
534e8d8bef9SDimitry Andric   const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size);
535e8d8bef9SDimitry Andric 
536fe6060f1SDimitry Andric   if (beg_aligned >= end_aligned) {
537349cc55cSDimitry Andric     WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
538fe6060f1SDimitry Andric   } else {
539fe6060f1SDimitry Andric     if (beg_aligned != beg_shadow_addr)
540349cc55cSDimitry Andric       WriteZeroShadowInRange(beg_shadow_addr, beg_aligned);
541fe6060f1SDimitry Andric     if (end_aligned != end_shadow_addr)
542349cc55cSDimitry Andric       WriteZeroShadowInRange(end_aligned, end_shadow_addr);
543fe6060f1SDimitry Andric     if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
544fe6060f1SDimitry Andric       Die();
545fe6060f1SDimitry Andric   }
546fe6060f1SDimitry Andric }
547e8d8bef9SDimitry Andric 
548fe6060f1SDimitry Andric void SetShadow(dfsan_label label, void *addr, uptr size, dfsan_origin origin) {
549fe6060f1SDimitry Andric   if (0 != label) {
550fe6060f1SDimitry Andric     const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
551349cc55cSDimitry Andric     internal_memset((void *)beg_shadow_addr, label, size);
552fe6060f1SDimitry Andric     if (dfsan_get_track_origins())
553fe6060f1SDimitry Andric       SetOrigin(addr, size, origin);
554fe6060f1SDimitry Andric     return;
555fe6060f1SDimitry Andric   }
556fe6060f1SDimitry Andric 
557fe6060f1SDimitry Andric   if (dfsan_get_track_origins())
558fe6060f1SDimitry Andric     ReleaseOrigins(addr, size);
559fe6060f1SDimitry Andric 
560fe6060f1SDimitry Andric   ReleaseOrClearShadows(addr, size);
561fe6060f1SDimitry Andric }
562fe6060f1SDimitry Andric 
563349cc55cSDimitry Andric }  // namespace __dfsan
564349cc55cSDimitry Andric 
565349cc55cSDimitry Andric // If the label s is tainted, set the size bytes from the address p to be a new
566349cc55cSDimitry Andric // origin chain with the previous ID o and the current stack trace. This is
567349cc55cSDimitry Andric // used by instrumentation to reduce code size when too much code is inserted.
568349cc55cSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin(
569349cc55cSDimitry Andric     dfsan_label s, void *p, uptr size, dfsan_origin o) {
570349cc55cSDimitry Andric   if (UNLIKELY(s)) {
57106c3fb27SDimitry Andric     GET_CALLER_PC_BP;
572349cc55cSDimitry Andric     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
573349cc55cSDimitry Andric     SetOrigin(p, size, ChainOrigin(o, &stack));
574349cc55cSDimitry Andric   }
575349cc55cSDimitry Andric }
576349cc55cSDimitry Andric 
577fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(
578fe6060f1SDimitry Andric     dfsan_label label, dfsan_origin origin, void *addr, uptr size) {
579349cc55cSDimitry Andric   __dfsan::SetShadow(label, addr, size, origin);
580e8d8bef9SDimitry Andric }
581e8d8bef9SDimitry Andric 
58268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
58368d75effSDimitry Andric void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
584fe6060f1SDimitry Andric   dfsan_origin init_origin = 0;
585fe6060f1SDimitry Andric   if (label && dfsan_get_track_origins()) {
586fe6060f1SDimitry Andric     GET_CALLER_PC_BP;
587fe6060f1SDimitry Andric     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
588fe6060f1SDimitry Andric     init_origin = ChainOrigin(0, &stack, true);
589fe6060f1SDimitry Andric   }
590349cc55cSDimitry Andric   __dfsan::SetShadow(label, addr, size, init_origin);
59168d75effSDimitry Andric }
59268d75effSDimitry Andric 
59368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
59468d75effSDimitry Andric void dfsan_add_label(dfsan_label label, void *addr, uptr size) {
595fe6060f1SDimitry Andric   if (0 == label)
596fe6060f1SDimitry Andric     return;
597fe6060f1SDimitry Andric 
598fe6060f1SDimitry Andric   if (dfsan_get_track_origins()) {
599fe6060f1SDimitry Andric     GET_CALLER_PC_BP;
600fe6060f1SDimitry Andric     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
601fe6060f1SDimitry Andric     dfsan_origin init_origin = ChainOrigin(0, &stack, true);
602fe6060f1SDimitry Andric     SetOrigin(addr, size, init_origin);
603fe6060f1SDimitry Andric   }
604fe6060f1SDimitry Andric 
60568d75effSDimitry Andric   for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
606fe6060f1SDimitry Andric     *labelp |= label;
60768d75effSDimitry Andric }
60868d75effSDimitry Andric 
60968d75effSDimitry Andric // Unlike the other dfsan interface functions the behavior of this function
61068d75effSDimitry Andric // depends on the label of one of its arguments.  Hence it is implemented as a
61168d75effSDimitry Andric // custom function.
61268d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
61368d75effSDimitry Andric __dfsw_dfsan_get_label(long data, dfsan_label data_label,
61468d75effSDimitry Andric                        dfsan_label *ret_label) {
61568d75effSDimitry Andric   *ret_label = 0;
61668d75effSDimitry Andric   return data_label;
61768d75effSDimitry Andric }
61868d75effSDimitry Andric 
619fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfso_dfsan_get_label(
620fe6060f1SDimitry Andric     long data, dfsan_label data_label, dfsan_label *ret_label,
621fe6060f1SDimitry Andric     dfsan_origin data_origin, dfsan_origin *ret_origin) {
622fe6060f1SDimitry Andric   *ret_label = 0;
623fe6060f1SDimitry Andric   *ret_origin = 0;
624fe6060f1SDimitry Andric   return data_label;
625fe6060f1SDimitry Andric }
626fe6060f1SDimitry Andric 
627fe6060f1SDimitry Andric // This function is used if dfsan_get_origin is called when origin tracking is
628fe6060f1SDimitry Andric // off.
629fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfsw_dfsan_get_origin(
630fe6060f1SDimitry Andric     long data, dfsan_label data_label, dfsan_label *ret_label) {
631fe6060f1SDimitry Andric   *ret_label = 0;
632fe6060f1SDimitry Andric   return 0;
633fe6060f1SDimitry Andric }
634fe6060f1SDimitry Andric 
635fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfso_dfsan_get_origin(
636fe6060f1SDimitry Andric     long data, dfsan_label data_label, dfsan_label *ret_label,
637fe6060f1SDimitry Andric     dfsan_origin data_origin, dfsan_origin *ret_origin) {
638fe6060f1SDimitry Andric   *ret_label = 0;
639fe6060f1SDimitry Andric   *ret_origin = 0;
640fe6060f1SDimitry Andric   return data_origin;
641fe6060f1SDimitry Andric }
642fe6060f1SDimitry Andric 
64368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
64468d75effSDimitry Andric dfsan_read_label(const void *addr, uptr size) {
64568d75effSDimitry Andric   if (size == 0)
64668d75effSDimitry Andric     return 0;
64768d75effSDimitry Andric   return __dfsan_union_load(shadow_for(addr), size);
64868d75effSDimitry Andric }
64968d75effSDimitry Andric 
650fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
651fe6060f1SDimitry Andric dfsan_read_origin_of_first_taint(const void *addr, uptr size) {
652fe6060f1SDimitry Andric   return GetOriginIfTainted((uptr)addr, size);
653fe6060f1SDimitry Andric }
654fe6060f1SDimitry Andric 
655fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label_origin(dfsan_label label,
656fe6060f1SDimitry Andric                                                           dfsan_origin origin,
657fe6060f1SDimitry Andric                                                           void *addr,
658fe6060f1SDimitry Andric                                                           uptr size) {
659fe6060f1SDimitry Andric   __dfsan_set_label(label, origin, addr, size);
66068d75effSDimitry Andric }
66168d75effSDimitry Andric 
66268d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int
66368d75effSDimitry Andric dfsan_has_label(dfsan_label label, dfsan_label elem) {
664fe6060f1SDimitry Andric   return (label & elem) == elem;
66568d75effSDimitry Andric }
66668d75effSDimitry Andric 
66704eeddc0SDimitry Andric namespace __dfsan {
66804eeddc0SDimitry Andric 
66904eeddc0SDimitry Andric typedef void (*dfsan_conditional_callback_t)(dfsan_label label,
67004eeddc0SDimitry Andric                                              dfsan_origin origin);
67104eeddc0SDimitry Andric static dfsan_conditional_callback_t conditional_callback = nullptr;
67204eeddc0SDimitry Andric static dfsan_label labels_in_signal_conditional = 0;
67304eeddc0SDimitry Andric 
67404eeddc0SDimitry Andric static void ConditionalCallback(dfsan_label label, dfsan_origin origin) {
67504eeddc0SDimitry Andric   // Programs have many branches. For efficiency the conditional sink callback
67604eeddc0SDimitry Andric   // handler needs to ignore as many as possible as early as possible.
67704eeddc0SDimitry Andric   if (label == 0) {
67804eeddc0SDimitry Andric     return;
67904eeddc0SDimitry Andric   }
68004eeddc0SDimitry Andric   if (conditional_callback == nullptr) {
68104eeddc0SDimitry Andric     return;
68204eeddc0SDimitry Andric   }
68304eeddc0SDimitry Andric 
68404eeddc0SDimitry Andric   // This initial ConditionalCallback handler needs to be in here in dfsan
68504eeddc0SDimitry Andric   // runtime (rather than being an entirely user implemented hook) so that it
68604eeddc0SDimitry Andric   // has access to dfsan thread information.
68704eeddc0SDimitry Andric   DFsanThread *t = GetCurrentThread();
68804eeddc0SDimitry Andric   // A callback operation which does useful work (like record the flow) will
68904eeddc0SDimitry Andric   // likely be too long executed in a signal handler.
69004eeddc0SDimitry Andric   if (t && t->InSignalHandler()) {
69104eeddc0SDimitry Andric     // Record set of labels used in signal handler for completeness.
69204eeddc0SDimitry Andric     labels_in_signal_conditional |= label;
69304eeddc0SDimitry Andric     return;
69404eeddc0SDimitry Andric   }
69504eeddc0SDimitry Andric 
69604eeddc0SDimitry Andric   conditional_callback(label, origin);
69704eeddc0SDimitry Andric }
69804eeddc0SDimitry Andric 
69904eeddc0SDimitry Andric }  // namespace __dfsan
70004eeddc0SDimitry Andric 
70104eeddc0SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
70204eeddc0SDimitry Andric __dfsan_conditional_callback_origin(dfsan_label label, dfsan_origin origin) {
70304eeddc0SDimitry Andric   __dfsan::ConditionalCallback(label, origin);
70404eeddc0SDimitry Andric }
70504eeddc0SDimitry Andric 
70604eeddc0SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_conditional_callback(
70704eeddc0SDimitry Andric     dfsan_label label) {
70804eeddc0SDimitry Andric   __dfsan::ConditionalCallback(label, 0);
70904eeddc0SDimitry Andric }
71004eeddc0SDimitry Andric 
71104eeddc0SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_conditional_callback(
71204eeddc0SDimitry Andric     __dfsan::dfsan_conditional_callback_t callback) {
71304eeddc0SDimitry Andric   __dfsan::conditional_callback = callback;
71404eeddc0SDimitry Andric }
71504eeddc0SDimitry Andric 
71604eeddc0SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
71704eeddc0SDimitry Andric dfsan_get_labels_in_signal_conditional() {
71804eeddc0SDimitry Andric   return __dfsan::labels_in_signal_conditional;
71904eeddc0SDimitry Andric }
72004eeddc0SDimitry Andric 
721bdd1243dSDimitry Andric namespace __dfsan {
722bdd1243dSDimitry Andric 
723bdd1243dSDimitry Andric typedef void (*dfsan_reaches_function_callback_t)(dfsan_label label,
724bdd1243dSDimitry Andric                                                   dfsan_origin origin,
725bdd1243dSDimitry Andric                                                   const char *file,
726bdd1243dSDimitry Andric                                                   unsigned int line,
727bdd1243dSDimitry Andric                                                   const char *function);
728bdd1243dSDimitry Andric static dfsan_reaches_function_callback_t reaches_function_callback = nullptr;
729bdd1243dSDimitry Andric static dfsan_label labels_in_signal_reaches_function = 0;
730bdd1243dSDimitry Andric 
731bdd1243dSDimitry Andric static void ReachesFunctionCallback(dfsan_label label, dfsan_origin origin,
732bdd1243dSDimitry Andric                                     const char *file, unsigned int line,
733bdd1243dSDimitry Andric                                     const char *function) {
734bdd1243dSDimitry Andric   if (label == 0) {
735bdd1243dSDimitry Andric     return;
736bdd1243dSDimitry Andric   }
737bdd1243dSDimitry Andric   if (reaches_function_callback == nullptr) {
738bdd1243dSDimitry Andric     return;
739bdd1243dSDimitry Andric   }
740bdd1243dSDimitry Andric 
741bdd1243dSDimitry Andric   // This initial ReachesFunctionCallback handler needs to be in here in dfsan
742bdd1243dSDimitry Andric   // runtime (rather than being an entirely user implemented hook) so that it
743bdd1243dSDimitry Andric   // has access to dfsan thread information.
744bdd1243dSDimitry Andric   DFsanThread *t = GetCurrentThread();
745bdd1243dSDimitry Andric   // A callback operation which does useful work (like record the flow) will
746bdd1243dSDimitry Andric   // likely be too long executed in a signal handler.
747bdd1243dSDimitry Andric   if (t && t->InSignalHandler()) {
748bdd1243dSDimitry Andric     // Record set of labels used in signal handler for completeness.
749bdd1243dSDimitry Andric     labels_in_signal_reaches_function |= label;
750bdd1243dSDimitry Andric     return;
751bdd1243dSDimitry Andric   }
752bdd1243dSDimitry Andric 
753bdd1243dSDimitry Andric   reaches_function_callback(label, origin, file, line, function);
754bdd1243dSDimitry Andric }
755bdd1243dSDimitry Andric 
756bdd1243dSDimitry Andric }  // namespace __dfsan
757bdd1243dSDimitry Andric 
758bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
759bdd1243dSDimitry Andric __dfsan_reaches_function_callback_origin(dfsan_label label, dfsan_origin origin,
760bdd1243dSDimitry Andric                                          const char *file, unsigned int line,
761bdd1243dSDimitry Andric                                          const char *function) {
762bdd1243dSDimitry Andric   __dfsan::ReachesFunctionCallback(label, origin, file, line, function);
763bdd1243dSDimitry Andric }
764bdd1243dSDimitry Andric 
765bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
766bdd1243dSDimitry Andric __dfsan_reaches_function_callback(dfsan_label label, const char *file,
767bdd1243dSDimitry Andric                                   unsigned int line, const char *function) {
768bdd1243dSDimitry Andric   __dfsan::ReachesFunctionCallback(label, 0, file, line, function);
769bdd1243dSDimitry Andric }
770bdd1243dSDimitry Andric 
771bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
772bdd1243dSDimitry Andric dfsan_set_reaches_function_callback(
773bdd1243dSDimitry Andric     __dfsan::dfsan_reaches_function_callback_t callback) {
774bdd1243dSDimitry Andric   __dfsan::reaches_function_callback = callback;
775bdd1243dSDimitry Andric }
776bdd1243dSDimitry Andric 
777bdd1243dSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
778bdd1243dSDimitry Andric dfsan_get_labels_in_signal_reaches_function() {
779bdd1243dSDimitry Andric   return __dfsan::labels_in_signal_reaches_function;
780bdd1243dSDimitry Andric }
781bdd1243dSDimitry Andric 
782fe6060f1SDimitry Andric class Decorator : public __sanitizer::SanitizerCommonDecorator {
783fe6060f1SDimitry Andric  public:
784fe6060f1SDimitry Andric   Decorator() : SanitizerCommonDecorator() {}
785fe6060f1SDimitry Andric   const char *Origin() const { return Magenta(); }
786fe6060f1SDimitry Andric };
787fe6060f1SDimitry Andric 
788fe6060f1SDimitry Andric namespace {
789fe6060f1SDimitry Andric 
790fe6060f1SDimitry Andric void PrintNoOriginTrackingWarning() {
791fe6060f1SDimitry Andric   Decorator d;
792fe6060f1SDimitry Andric   Printf(
793fe6060f1SDimitry Andric       "  %sDFSan: origin tracking is not enabled. Did you specify the "
794fe6060f1SDimitry Andric       "-dfsan-track-origins=1 option?%s\n",
795fe6060f1SDimitry Andric       d.Warning(), d.Default());
79668d75effSDimitry Andric }
79768d75effSDimitry Andric 
798fe6060f1SDimitry Andric void PrintNoTaintWarning(const void *address) {
799fe6060f1SDimitry Andric   Decorator d;
800fe6060f1SDimitry Andric   Printf("  %sDFSan: no tainted value at %x%s\n", d.Warning(), address,
801fe6060f1SDimitry Andric          d.Default());
80268d75effSDimitry Andric }
80368d75effSDimitry Andric 
804fe6060f1SDimitry Andric void PrintInvalidOriginWarning(dfsan_label label, const void *address) {
805fe6060f1SDimitry Andric   Decorator d;
806fe6060f1SDimitry Andric   Printf(
807fe6060f1SDimitry Andric       "  %sTaint value 0x%x (at %p) has invalid origin tracking. This can "
808fe6060f1SDimitry Andric       "be a DFSan bug.%s\n",
809fe6060f1SDimitry Andric       d.Warning(), label, address, d.Default());
81068d75effSDimitry Andric }
81168d75effSDimitry Andric 
8120eae32dcSDimitry Andric void PrintInvalidOriginIdWarning(dfsan_origin origin) {
813fe6060f1SDimitry Andric   Decorator d;
8140eae32dcSDimitry Andric   Printf(
8150eae32dcSDimitry Andric       "  %sOrigin Id %d has invalid origin tracking. This can "
8160eae32dcSDimitry Andric       "be a DFSan bug.%s\n",
8170eae32dcSDimitry Andric       d.Warning(), origin, d.Default());
8180eae32dcSDimitry Andric }
819fe6060f1SDimitry Andric 
8200eae32dcSDimitry Andric bool PrintOriginTraceFramesToStr(Origin o, InternalScopedString *out) {
8210eae32dcSDimitry Andric   Decorator d;
822fe6060f1SDimitry Andric   bool found = false;
823fe6060f1SDimitry Andric 
824fe6060f1SDimitry Andric   while (o.isChainedOrigin()) {
825fe6060f1SDimitry Andric     StackTrace stack;
826fe6060f1SDimitry Andric     dfsan_origin origin_id = o.raw_id();
827fe6060f1SDimitry Andric     o = o.getNextChainedOrigin(&stack);
828fe6060f1SDimitry Andric     if (o.isChainedOrigin())
8295f757f3fSDimitry Andric       out->AppendF(
830fe6060f1SDimitry Andric           "  %sOrigin value: 0x%x, Taint value was stored to memory at%s\n",
831fe6060f1SDimitry Andric           d.Origin(), origin_id, d.Default());
832fe6060f1SDimitry Andric     else
8335f757f3fSDimitry Andric       out->AppendF("  %sOrigin value: 0x%x, Taint value was created at%s\n",
834fe6060f1SDimitry Andric                    d.Origin(), origin_id, d.Default());
835fe6060f1SDimitry Andric 
836fe6060f1SDimitry Andric     // Includes a trailing newline, so no need to add it again.
837fe6060f1SDimitry Andric     stack.PrintTo(out);
838fe6060f1SDimitry Andric     found = true;
839fe6060f1SDimitry Andric   }
840fe6060f1SDimitry Andric 
841fe6060f1SDimitry Andric   return found;
842fe6060f1SDimitry Andric }
843fe6060f1SDimitry Andric 
8440eae32dcSDimitry Andric bool PrintOriginTraceToStr(const void *addr, const char *description,
8450eae32dcSDimitry Andric                            InternalScopedString *out) {
8460eae32dcSDimitry Andric   CHECK(out);
8470eae32dcSDimitry Andric   CHECK(dfsan_get_track_origins());
8480eae32dcSDimitry Andric   Decorator d;
8490eae32dcSDimitry Andric 
8500eae32dcSDimitry Andric   const dfsan_label label = *__dfsan::shadow_for(addr);
8510eae32dcSDimitry Andric   CHECK(label);
8520eae32dcSDimitry Andric 
8530eae32dcSDimitry Andric   const dfsan_origin origin = *__dfsan::origin_for(addr);
8540eae32dcSDimitry Andric 
8555f757f3fSDimitry Andric   out->AppendF("  %sTaint value 0x%x (at %p) origin tracking (%s)%s\n",
8560eae32dcSDimitry Andric                d.Origin(), label, addr, description ? description : "",
8570eae32dcSDimitry Andric                d.Default());
8580eae32dcSDimitry Andric 
8590eae32dcSDimitry Andric   Origin o = Origin::FromRawId(origin);
8600eae32dcSDimitry Andric   return PrintOriginTraceFramesToStr(o, out);
8610eae32dcSDimitry Andric }
8620eae32dcSDimitry Andric 
863fe6060f1SDimitry Andric }  // namespace
864fe6060f1SDimitry Andric 
865fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace(
866fe6060f1SDimitry Andric     const void *addr, const char *description) {
867fe6060f1SDimitry Andric   if (!dfsan_get_track_origins()) {
868fe6060f1SDimitry Andric     PrintNoOriginTrackingWarning();
869fe6060f1SDimitry Andric     return;
870fe6060f1SDimitry Andric   }
871fe6060f1SDimitry Andric 
872fe6060f1SDimitry Andric   const dfsan_label label = *__dfsan::shadow_for(addr);
873fe6060f1SDimitry Andric   if (!label) {
874fe6060f1SDimitry Andric     PrintNoTaintWarning(addr);
875fe6060f1SDimitry Andric     return;
876fe6060f1SDimitry Andric   }
877fe6060f1SDimitry Andric 
878fe6060f1SDimitry Andric   InternalScopedString trace;
879fe6060f1SDimitry Andric   bool success = PrintOriginTraceToStr(addr, description, &trace);
880fe6060f1SDimitry Andric 
881fe6060f1SDimitry Andric   if (trace.length())
882fe6060f1SDimitry Andric     Printf("%s", trace.data());
883fe6060f1SDimitry Andric 
884fe6060f1SDimitry Andric   if (!success)
885fe6060f1SDimitry Andric     PrintInvalidOriginWarning(label, addr);
886fe6060f1SDimitry Andric }
887fe6060f1SDimitry Andric 
888349cc55cSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
889fe6060f1SDimitry Andric dfsan_sprint_origin_trace(const void *addr, const char *description,
890349cc55cSDimitry Andric                           char *out_buf, uptr out_buf_size) {
891fe6060f1SDimitry Andric   CHECK(out_buf);
892fe6060f1SDimitry Andric 
893fe6060f1SDimitry Andric   if (!dfsan_get_track_origins()) {
894fe6060f1SDimitry Andric     PrintNoOriginTrackingWarning();
895fe6060f1SDimitry Andric     return 0;
896fe6060f1SDimitry Andric   }
897fe6060f1SDimitry Andric 
898fe6060f1SDimitry Andric   const dfsan_label label = *__dfsan::shadow_for(addr);
899fe6060f1SDimitry Andric   if (!label) {
900fe6060f1SDimitry Andric     PrintNoTaintWarning(addr);
901fe6060f1SDimitry Andric     return 0;
902fe6060f1SDimitry Andric   }
903fe6060f1SDimitry Andric 
904fe6060f1SDimitry Andric   InternalScopedString trace;
905fe6060f1SDimitry Andric   bool success = PrintOriginTraceToStr(addr, description, &trace);
906fe6060f1SDimitry Andric 
907fe6060f1SDimitry Andric   if (!success) {
908fe6060f1SDimitry Andric     PrintInvalidOriginWarning(label, addr);
909fe6060f1SDimitry Andric     return 0;
910fe6060f1SDimitry Andric   }
911fe6060f1SDimitry Andric 
912fe6060f1SDimitry Andric   if (out_buf_size) {
913fe6060f1SDimitry Andric     internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
914fe6060f1SDimitry Andric     out_buf[out_buf_size - 1] = '\0';
915fe6060f1SDimitry Andric   }
916fe6060f1SDimitry Andric 
917fe6060f1SDimitry Andric   return trace.length();
918fe6060f1SDimitry Andric }
919fe6060f1SDimitry Andric 
9200eae32dcSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_id_trace(
9210eae32dcSDimitry Andric     dfsan_origin origin) {
9220eae32dcSDimitry Andric   if (!dfsan_get_track_origins()) {
9230eae32dcSDimitry Andric     PrintNoOriginTrackingWarning();
9240eae32dcSDimitry Andric     return;
9250eae32dcSDimitry Andric   }
9260eae32dcSDimitry Andric   Origin o = Origin::FromRawId(origin);
9270eae32dcSDimitry Andric 
9280eae32dcSDimitry Andric   InternalScopedString trace;
9290eae32dcSDimitry Andric   bool success = PrintOriginTraceFramesToStr(o, &trace);
9300eae32dcSDimitry Andric 
9310eae32dcSDimitry Andric   if (trace.length())
9320eae32dcSDimitry Andric     Printf("%s", trace.data());
9330eae32dcSDimitry Andric 
9340eae32dcSDimitry Andric   if (!success)
9350eae32dcSDimitry Andric     PrintInvalidOriginIdWarning(origin);
9360eae32dcSDimitry Andric }
9370eae32dcSDimitry Andric 
9380eae32dcSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_sprint_origin_id_trace(
9390eae32dcSDimitry Andric     dfsan_origin origin, char *out_buf, uptr out_buf_size) {
9400eae32dcSDimitry Andric   CHECK(out_buf);
9410eae32dcSDimitry Andric 
9420eae32dcSDimitry Andric   if (!dfsan_get_track_origins()) {
9430eae32dcSDimitry Andric     PrintNoOriginTrackingWarning();
9440eae32dcSDimitry Andric     return 0;
9450eae32dcSDimitry Andric   }
9460eae32dcSDimitry Andric   Origin o = Origin::FromRawId(origin);
9470eae32dcSDimitry Andric 
9480eae32dcSDimitry Andric   InternalScopedString trace;
9490eae32dcSDimitry Andric   bool success = PrintOriginTraceFramesToStr(o, &trace);
9500eae32dcSDimitry Andric 
9510eae32dcSDimitry Andric   if (!success) {
9520eae32dcSDimitry Andric     PrintInvalidOriginIdWarning(origin);
9530eae32dcSDimitry Andric     return 0;
9540eae32dcSDimitry Andric   }
9550eae32dcSDimitry Andric 
9560eae32dcSDimitry Andric   if (out_buf_size) {
9570eae32dcSDimitry Andric     internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
9580eae32dcSDimitry Andric     out_buf[out_buf_size - 1] = '\0';
9590eae32dcSDimitry Andric   }
9600eae32dcSDimitry Andric 
9610eae32dcSDimitry Andric   return trace.length();
9620eae32dcSDimitry Andric }
9630eae32dcSDimitry Andric 
964fe6060f1SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
965fe6060f1SDimitry Andric dfsan_get_init_origin(const void *addr) {
966fe6060f1SDimitry Andric   if (!dfsan_get_track_origins())
967fe6060f1SDimitry Andric     return 0;
968fe6060f1SDimitry Andric 
969fe6060f1SDimitry Andric   const dfsan_label label = *__dfsan::shadow_for(addr);
970fe6060f1SDimitry Andric   if (!label)
971fe6060f1SDimitry Andric     return 0;
972fe6060f1SDimitry Andric 
973fe6060f1SDimitry Andric   const dfsan_origin origin = *__dfsan::origin_for(addr);
974fe6060f1SDimitry Andric 
975fe6060f1SDimitry Andric   Origin o = Origin::FromRawId(origin);
976fe6060f1SDimitry Andric   dfsan_origin origin_id = o.raw_id();
977fe6060f1SDimitry Andric   while (o.isChainedOrigin()) {
978fe6060f1SDimitry Andric     StackTrace stack;
979fe6060f1SDimitry Andric     origin_id = o.raw_id();
980fe6060f1SDimitry Andric     o = o.getNextChainedOrigin(&stack);
981fe6060f1SDimitry Andric   }
982fe6060f1SDimitry Andric   return origin_id;
983fe6060f1SDimitry Andric }
984e8d8bef9SDimitry Andric 
985e8d8bef9SDimitry Andric void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
986e8d8bef9SDimitry Andric                                                  void *context,
987e8d8bef9SDimitry Andric                                                  bool request_fast,
988e8d8bef9SDimitry Andric                                                  u32 max_depth) {
989fe6060f1SDimitry Andric   using namespace __dfsan;
990fe6060f1SDimitry Andric   DFsanThread *t = GetCurrentThread();
991fe6060f1SDimitry Andric   if (!t || !StackTrace::WillUseFastUnwind(request_fast)) {
992fe6060f1SDimitry Andric     return Unwind(max_depth, pc, bp, context, 0, 0, false);
993fe6060f1SDimitry Andric   }
994fe6060f1SDimitry Andric   Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true);
995e8d8bef9SDimitry Andric }
996e8d8bef9SDimitry Andric 
997e8d8bef9SDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() {
998fe6060f1SDimitry Andric   GET_CALLER_PC_BP;
999fe6060f1SDimitry Andric   GET_STORE_STACK_TRACE_PC_BP(pc, bp);
1000e8d8bef9SDimitry Andric   stack.Print();
1001e8d8bef9SDimitry Andric }
1002e8d8bef9SDimitry Andric 
1003349cc55cSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
1004349cc55cSDimitry Andric dfsan_sprint_stack_trace(char *out_buf, uptr out_buf_size) {
1005fe6060f1SDimitry Andric   CHECK(out_buf);
1006fe6060f1SDimitry Andric   GET_CALLER_PC_BP;
1007fe6060f1SDimitry Andric   GET_STORE_STACK_TRACE_PC_BP(pc, bp);
1008fe6060f1SDimitry Andric   return stack.PrintTo(out_buf, out_buf_size);
1009fe6060f1SDimitry Andric }
1010fe6060f1SDimitry Andric 
101168d75effSDimitry Andric void Flags::SetDefaults() {
101268d75effSDimitry Andric #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
101368d75effSDimitry Andric #include "dfsan_flags.inc"
101468d75effSDimitry Andric #undef DFSAN_FLAG
101568d75effSDimitry Andric }
101668d75effSDimitry Andric 
101768d75effSDimitry Andric static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
101868d75effSDimitry Andric #define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
101968d75effSDimitry Andric   RegisterFlag(parser, #Name, Description, &f->Name);
102068d75effSDimitry Andric #include "dfsan_flags.inc"
102168d75effSDimitry Andric #undef DFSAN_FLAG
102268d75effSDimitry Andric }
102368d75effSDimitry Andric 
102468d75effSDimitry Andric static void InitializeFlags() {
102568d75effSDimitry Andric   SetCommonFlagsDefaults();
1026fe6060f1SDimitry Andric   {
1027fe6060f1SDimitry Andric     CommonFlags cf;
1028fe6060f1SDimitry Andric     cf.CopyFrom(*common_flags());
1029fe6060f1SDimitry Andric     cf.intercept_tls_get_addr = true;
1030fe6060f1SDimitry Andric     OverrideCommonFlags(cf);
1031fe6060f1SDimitry Andric   }
103268d75effSDimitry Andric   flags().SetDefaults();
103368d75effSDimitry Andric 
103468d75effSDimitry Andric   FlagParser parser;
103568d75effSDimitry Andric   RegisterCommonFlags(&parser);
103668d75effSDimitry Andric   RegisterDfsanFlags(&parser, &flags());
103768d75effSDimitry Andric   parser.ParseStringFromEnv("DFSAN_OPTIONS");
103868d75effSDimitry Andric   InitializeCommonFlags();
103968d75effSDimitry Andric   if (Verbosity()) ReportUnrecognizedFlags();
104068d75effSDimitry Andric   if (common_flags()->help) parser.PrintFlagDescriptions();
104168d75effSDimitry Andric }
104268d75effSDimitry Andric 
1043fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1044fe6060f1SDimitry Andric void dfsan_clear_arg_tls(uptr offset, uptr size) {
1045fe6060f1SDimitry Andric   internal_memset((void *)((uptr)__dfsan_arg_tls + offset), 0, size);
104668d75effSDimitry Andric }
104768d75effSDimitry Andric 
1048fe6060f1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1049fe6060f1SDimitry Andric void dfsan_clear_thread_local_state() {
1050fe6060f1SDimitry Andric   internal_memset(__dfsan_arg_tls, 0, sizeof(__dfsan_arg_tls));
1051fe6060f1SDimitry Andric   internal_memset(__dfsan_retval_tls, 0, sizeof(__dfsan_retval_tls));
105268d75effSDimitry Andric 
1053fe6060f1SDimitry Andric   if (dfsan_get_track_origins()) {
1054fe6060f1SDimitry Andric     internal_memset(__dfsan_arg_origin_tls, 0, sizeof(__dfsan_arg_origin_tls));
1055fe6060f1SDimitry Andric     internal_memset(&__dfsan_retval_origin_tls, 0,
1056fe6060f1SDimitry Andric                     sizeof(__dfsan_retval_origin_tls));
105768d75effSDimitry Andric   }
105868d75effSDimitry Andric }
105968d75effSDimitry Andric 
106081ad6265SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
106181ad6265SDimitry Andric void dfsan_set_arg_tls(uptr offset, dfsan_label label) {
106281ad6265SDimitry Andric   // 2x to match ShadowTLSAlignment.
106381ad6265SDimitry Andric   // ShadowTLSAlignment should probably be changed.
106481ad6265SDimitry Andric   // TODO: Consider reducing ShadowTLSAlignment to 1.
106581ad6265SDimitry Andric   // Aligning to 2 bytes is probably a remnant of fast16 mode.
106681ad6265SDimitry Andric   ((dfsan_label *)__dfsan_arg_tls)[offset * 2] = label;
106781ad6265SDimitry Andric }
106881ad6265SDimitry Andric 
106981ad6265SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
107081ad6265SDimitry Andric void dfsan_set_arg_origin_tls(uptr offset, dfsan_origin o) {
107181ad6265SDimitry Andric   __dfsan_arg_origin_tls[offset] = o;
107281ad6265SDimitry Andric }
107381ad6265SDimitry Andric 
107468d75effSDimitry Andric extern "C" void dfsan_flush() {
1075fe6060f1SDimitry Andric   const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
1076fe6060f1SDimitry Andric   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
1077fe6060f1SDimitry Andric     uptr start = kMemoryLayout[i].start;
1078fe6060f1SDimitry Andric     uptr end = kMemoryLayout[i].end;
1079fe6060f1SDimitry Andric     uptr size = end - start;
1080fe6060f1SDimitry Andric     MappingDesc::Type type = kMemoryLayout[i].type;
1081fe6060f1SDimitry Andric 
1082fe6060f1SDimitry Andric     if (type != MappingDesc::SHADOW && type != MappingDesc::ORIGIN)
1083fe6060f1SDimitry Andric       continue;
1084fe6060f1SDimitry Andric 
1085fe6060f1SDimitry Andric     // Check if the segment should be mapped based on platform constraints.
1086fe6060f1SDimitry Andric     if (start >= maxVirtualAddress)
1087fe6060f1SDimitry Andric       continue;
1088fe6060f1SDimitry Andric 
1089fe6060f1SDimitry Andric     if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) {
1090fe6060f1SDimitry Andric       Printf("FATAL: DataFlowSanitizer: failed to clear memory region\n");
109168d75effSDimitry Andric       Die();
109268d75effSDimitry Andric     }
1093fe6060f1SDimitry Andric   }
109404eeddc0SDimitry Andric   __dfsan::labels_in_signal_conditional = 0;
1095bdd1243dSDimitry Andric   __dfsan::labels_in_signal_reaches_function = 0;
1096fe6060f1SDimitry Andric }
109768d75effSDimitry Andric 
1098fe6060f1SDimitry Andric // TODO: CheckMemoryLayoutSanity is based on msan.
1099fe6060f1SDimitry Andric // Consider refactoring these into a shared implementation.
1100fe6060f1SDimitry Andric static void CheckMemoryLayoutSanity() {
1101fe6060f1SDimitry Andric   uptr prev_end = 0;
1102fe6060f1SDimitry Andric   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
1103fe6060f1SDimitry Andric     uptr start = kMemoryLayout[i].start;
1104fe6060f1SDimitry Andric     uptr end = kMemoryLayout[i].end;
1105fe6060f1SDimitry Andric     MappingDesc::Type type = kMemoryLayout[i].type;
1106fe6060f1SDimitry Andric     CHECK_LT(start, end);
1107fe6060f1SDimitry Andric     CHECK_EQ(prev_end, start);
1108fe6060f1SDimitry Andric     CHECK(addr_is_type(start, type));
1109fe6060f1SDimitry Andric     CHECK(addr_is_type((start + end) / 2, type));
1110fe6060f1SDimitry Andric     CHECK(addr_is_type(end - 1, type));
1111fe6060f1SDimitry Andric     if (type == MappingDesc::APP) {
1112fe6060f1SDimitry Andric       uptr addr = start;
1113fe6060f1SDimitry Andric       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
1114fe6060f1SDimitry Andric       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
1115fe6060f1SDimitry Andric       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
1116fe6060f1SDimitry Andric 
1117fe6060f1SDimitry Andric       addr = (start + end) / 2;
1118fe6060f1SDimitry Andric       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
1119fe6060f1SDimitry Andric       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
1120fe6060f1SDimitry Andric       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
1121fe6060f1SDimitry Andric 
1122fe6060f1SDimitry Andric       addr = end - 1;
1123fe6060f1SDimitry Andric       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
1124fe6060f1SDimitry Andric       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
1125fe6060f1SDimitry Andric       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
1126fe6060f1SDimitry Andric     }
1127fe6060f1SDimitry Andric     prev_end = end;
1128fe6060f1SDimitry Andric   }
1129fe6060f1SDimitry Andric }
1130fe6060f1SDimitry Andric 
1131fe6060f1SDimitry Andric // TODO: CheckMemoryRangeAvailability is based on msan.
1132fe6060f1SDimitry Andric // Consider refactoring these into a shared implementation.
1133*0fca6ea1SDimitry Andric static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {
1134fe6060f1SDimitry Andric   if (size > 0) {
1135fe6060f1SDimitry Andric     uptr end = beg + size - 1;
1136fe6060f1SDimitry Andric     if (!MemoryRangeIsAvailable(beg, end)) {
1137*0fca6ea1SDimitry Andric       if (verbose)
1138fe6060f1SDimitry Andric         Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
1139fe6060f1SDimitry Andric       return false;
1140fe6060f1SDimitry Andric     }
1141fe6060f1SDimitry Andric   }
1142fe6060f1SDimitry Andric   return true;
1143fe6060f1SDimitry Andric }
1144fe6060f1SDimitry Andric 
1145fe6060f1SDimitry Andric // TODO: ProtectMemoryRange is based on msan.
1146fe6060f1SDimitry Andric // Consider refactoring these into a shared implementation.
1147fe6060f1SDimitry Andric static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
1148fe6060f1SDimitry Andric   if (size > 0) {
1149fe6060f1SDimitry Andric     void *addr = MmapFixedNoAccess(beg, size, name);
1150fe6060f1SDimitry Andric     if (beg == 0 && addr) {
1151fe6060f1SDimitry Andric       // Depending on the kernel configuration, we may not be able to protect
1152fe6060f1SDimitry Andric       // the page at address zero.
1153fe6060f1SDimitry Andric       uptr gap = 16 * GetPageSizeCached();
1154fe6060f1SDimitry Andric       beg += gap;
1155fe6060f1SDimitry Andric       size -= gap;
1156fe6060f1SDimitry Andric       addr = MmapFixedNoAccess(beg, size, name);
1157fe6060f1SDimitry Andric     }
1158fe6060f1SDimitry Andric     if ((uptr)addr != beg) {
1159fe6060f1SDimitry Andric       uptr end = beg + size - 1;
1160fe6060f1SDimitry Andric       Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end,
1161fe6060f1SDimitry Andric              name);
1162fe6060f1SDimitry Andric       return false;
1163fe6060f1SDimitry Andric     }
1164fe6060f1SDimitry Andric   }
1165fe6060f1SDimitry Andric   return true;
1166fe6060f1SDimitry Andric }
1167fe6060f1SDimitry Andric 
1168fe6060f1SDimitry Andric // TODO: InitShadow is based on msan.
1169fe6060f1SDimitry Andric // Consider refactoring these into a shared implementation.
1170*0fca6ea1SDimitry Andric bool InitShadow(bool init_origins, bool dry_run) {
1171fe6060f1SDimitry Andric   // Let user know mapping parameters first.
1172349cc55cSDimitry Andric   VPrintf(1, "dfsan_init %p\n", (void *)&__dfsan::dfsan_init);
1173fe6060f1SDimitry Andric   for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
1174fe6060f1SDimitry Andric     VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
1175fe6060f1SDimitry Andric             kMemoryLayout[i].end - 1);
1176fe6060f1SDimitry Andric 
1177fe6060f1SDimitry Andric   CheckMemoryLayoutSanity();
1178fe6060f1SDimitry Andric 
1179fe6060f1SDimitry Andric   if (!MEM_IS_APP(&__dfsan::dfsan_init)) {
1180*0fca6ea1SDimitry Andric     if (!dry_run)
1181fe6060f1SDimitry Andric       Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
1182fe6060f1SDimitry Andric              (uptr)&__dfsan::dfsan_init);
1183fe6060f1SDimitry Andric     return false;
1184fe6060f1SDimitry Andric   }
1185fe6060f1SDimitry Andric 
1186fe6060f1SDimitry Andric   const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
1187fe6060f1SDimitry Andric 
1188fe6060f1SDimitry Andric   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
1189fe6060f1SDimitry Andric     uptr start = kMemoryLayout[i].start;
1190fe6060f1SDimitry Andric     uptr end = kMemoryLayout[i].end;
1191fe6060f1SDimitry Andric     uptr size = end - start;
1192fe6060f1SDimitry Andric     MappingDesc::Type type = kMemoryLayout[i].type;
1193fe6060f1SDimitry Andric 
1194fe6060f1SDimitry Andric     // Check if the segment should be mapped based on platform constraints.
1195fe6060f1SDimitry Andric     if (start >= maxVirtualAddress)
1196fe6060f1SDimitry Andric       continue;
1197fe6060f1SDimitry Andric 
1198fe6060f1SDimitry Andric     bool map = type == MappingDesc::SHADOW ||
1199fe6060f1SDimitry Andric                (init_origins && type == MappingDesc::ORIGIN);
1200fe6060f1SDimitry Andric     bool protect = type == MappingDesc::INVALID ||
1201fe6060f1SDimitry Andric                    (!init_origins && type == MappingDesc::ORIGIN);
1202fe6060f1SDimitry Andric     CHECK(!(map && protect));
1203*0fca6ea1SDimitry Andric     if (!map && !protect) {
1204*0fca6ea1SDimitry Andric       CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
1205*0fca6ea1SDimitry Andric 
1206*0fca6ea1SDimitry Andric       if (dry_run && type == MappingDesc::ALLOCATOR &&
1207*0fca6ea1SDimitry Andric           !CheckMemoryRangeAvailability(start, size, !dry_run))
1208*0fca6ea1SDimitry Andric         return false;
1209*0fca6ea1SDimitry Andric     }
1210fe6060f1SDimitry Andric     if (map) {
1211*0fca6ea1SDimitry Andric       if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
1212fe6060f1SDimitry Andric         return false;
1213*0fca6ea1SDimitry Andric       if (!dry_run &&
1214*0fca6ea1SDimitry Andric           !MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
1215fe6060f1SDimitry Andric         return false;
1216*0fca6ea1SDimitry Andric       if (!dry_run && common_flags()->use_madv_dontdump)
1217fe6060f1SDimitry Andric         DontDumpShadowMemory(start, size);
1218fe6060f1SDimitry Andric     }
1219fe6060f1SDimitry Andric     if (protect) {
1220*0fca6ea1SDimitry Andric       if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
1221fe6060f1SDimitry Andric         return false;
1222*0fca6ea1SDimitry Andric       if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))
1223fe6060f1SDimitry Andric         return false;
1224fe6060f1SDimitry Andric     }
1225fe6060f1SDimitry Andric   }
1226fe6060f1SDimitry Andric 
1227fe6060f1SDimitry Andric   return true;
1228fe6060f1SDimitry Andric }
1229fe6060f1SDimitry Andric 
1230*0fca6ea1SDimitry Andric bool InitShadowWithReExec(bool init_origins) {
1231*0fca6ea1SDimitry Andric   // Start with dry run: check layout is ok, but don't print warnings because
1232*0fca6ea1SDimitry Andric   // warning messages will cause tests to fail (even if we successfully re-exec
1233*0fca6ea1SDimitry Andric   // after the warning).
1234*0fca6ea1SDimitry Andric   bool success = InitShadow(init_origins, true);
1235*0fca6ea1SDimitry Andric   if (!success) {
1236*0fca6ea1SDimitry Andric #if SANITIZER_LINUX
1237*0fca6ea1SDimitry Andric     // Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.
1238*0fca6ea1SDimitry Andric     int old_personality = personality(0xffffffff);
1239*0fca6ea1SDimitry Andric     bool aslr_on =
1240*0fca6ea1SDimitry Andric         (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
1241*0fca6ea1SDimitry Andric 
1242*0fca6ea1SDimitry Andric     if (aslr_on) {
1243*0fca6ea1SDimitry Andric       VReport(1,
1244*0fca6ea1SDimitry Andric               "WARNING: DataflowSanitizer: memory layout is incompatible, "
1245*0fca6ea1SDimitry Andric               "possibly due to high-entropy ASLR.\n"
1246*0fca6ea1SDimitry Andric               "Re-execing with fixed virtual address space.\n"
1247*0fca6ea1SDimitry Andric               "N.B. reducing ASLR entropy is preferable.\n");
1248*0fca6ea1SDimitry Andric       CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
1249*0fca6ea1SDimitry Andric       ReExec();
1250*0fca6ea1SDimitry Andric     }
1251*0fca6ea1SDimitry Andric #endif
1252*0fca6ea1SDimitry Andric   }
1253*0fca6ea1SDimitry Andric 
1254*0fca6ea1SDimitry Andric   // The earlier dry run didn't actually map or protect anything. Run again in
1255*0fca6ea1SDimitry Andric   // non-dry run mode.
1256*0fca6ea1SDimitry Andric   return success && InitShadow(init_origins, false);
1257*0fca6ea1SDimitry Andric }
1258*0fca6ea1SDimitry Andric 
1259fe6060f1SDimitry Andric static void DFsanInit(int argc, char **argv, char **envp) {
1260fe6060f1SDimitry Andric   CHECK(!dfsan_init_is_running);
1261fe6060f1SDimitry Andric   if (dfsan_inited)
1262fe6060f1SDimitry Andric     return;
1263fe6060f1SDimitry Andric   dfsan_init_is_running = true;
1264fe6060f1SDimitry Andric   SanitizerToolName = "DataflowSanitizer";
1265fe6060f1SDimitry Andric 
1266fe6060f1SDimitry Andric   AvoidCVE_2016_2143();
1267fe6060f1SDimitry Andric 
126868d75effSDimitry Andric   InitializeFlags();
126968d75effSDimitry Andric 
1270fe6060f1SDimitry Andric   CheckASLR();
127168d75effSDimitry Andric 
1272*0fca6ea1SDimitry Andric   if (!InitShadowWithReExec(dfsan_get_track_origins())) {
1273*0fca6ea1SDimitry Andric     Printf("FATAL: DataflowSanitizer can not mmap the shadow memory.\n");
1274*0fca6ea1SDimitry Andric     DumpProcessMap();
1275*0fca6ea1SDimitry Andric     Die();
1276*0fca6ea1SDimitry Andric   }
127768d75effSDimitry Andric 
1278fe6060f1SDimitry Andric   initialize_interceptors();
127968d75effSDimitry Andric 
1280fe6060f1SDimitry Andric   // Set up threads
1281fe6060f1SDimitry Andric   DFsanTSDInit(DFsanTSDDtor);
128268d75effSDimitry Andric 
1283fe6060f1SDimitry Andric   dfsan_allocator_init();
128468d75effSDimitry Andric 
128581ad6265SDimitry Andric   DFsanThread *main_thread = DFsanThread::Create(nullptr, nullptr);
1286fe6060f1SDimitry Andric   SetCurrentThread(main_thread);
1287349cc55cSDimitry Andric   main_thread->Init();
1288fe6060f1SDimitry Andric 
1289fe6060f1SDimitry Andric   dfsan_init_is_running = false;
1290fe6060f1SDimitry Andric   dfsan_inited = true;
129168d75effSDimitry Andric }
129268d75effSDimitry Andric 
1293fe6060f1SDimitry Andric namespace __dfsan {
1294fe6060f1SDimitry Andric 
1295fe6060f1SDimitry Andric void dfsan_init() { DFsanInit(0, nullptr, nullptr); }
1296fe6060f1SDimitry Andric 
1297fe6060f1SDimitry Andric }  // namespace __dfsan
1298fe6060f1SDimitry Andric 
129968d75effSDimitry Andric #if SANITIZER_CAN_USE_PREINIT_ARRAY
1300fe6060f1SDimitry Andric __attribute__((section(".preinit_array"),
1301fe6060f1SDimitry Andric                used)) static void (*dfsan_init_ptr)(int, char **,
1302fe6060f1SDimitry Andric                                                     char **) = DFsanInit;
130368d75effSDimitry Andric #endif
1304