xref: /llvm-project/compiler-rt/lib/dfsan/dfsan.cpp (revision a0bb2e21c10bebcdb6bc6b8bc18f74dcf7c4b8b2)
1a9aa8137SNico Weber //===-- dfsan.cpp ---------------------------------------------------------===//
2a9aa8137SNico Weber //
3a9aa8137SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a9aa8137SNico Weber // See https://llvm.org/LICENSE.txt for license information.
5a9aa8137SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9aa8137SNico Weber //
7a9aa8137SNico Weber //===----------------------------------------------------------------------===//
8a9aa8137SNico Weber //
9a9aa8137SNico Weber // This file is a part of DataFlowSanitizer.
10a9aa8137SNico Weber //
11a9aa8137SNico Weber // DataFlowSanitizer runtime.  This file defines the public interface to
12a9aa8137SNico Weber // DataFlowSanitizer as well as the definition of certain runtime functions
13a9aa8137SNico Weber // called automatically by the compiler (specifically the instrumentation pass
14a9aa8137SNico Weber // in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
15a9aa8137SNico Weber //
16a9aa8137SNico Weber // The public interface is defined in include/sanitizer/dfsan_interface.h whose
17a9aa8137SNico Weber // functions are prefixed dfsan_ while the compiler interface functions are
18a9aa8137SNico Weber // prefixed __dfsan_.
19a9aa8137SNico Weber //===----------------------------------------------------------------------===//
20a9aa8137SNico Weber 
21e2d0b44aSMatt Morehouse #include "dfsan/dfsan.h"
22e2d0b44aSMatt Morehouse 
232d9c6e10SJianzhou Zhao #include "dfsan/dfsan_chained_origin_depot.h"
242d9c6e10SJianzhou Zhao #include "dfsan/dfsan_flags.h"
252d9c6e10SJianzhou Zhao #include "dfsan/dfsan_origin.h"
260f3fd3b2SJianzhou Zhao #include "dfsan/dfsan_thread.h"
27a9aa8137SNico Weber #include "sanitizer_common/sanitizer_atomic.h"
28a9aa8137SNico Weber #include "sanitizer_common/sanitizer_common.h"
29a9aa8137SNico Weber #include "sanitizer_common/sanitizer_file.h"
30a9aa8137SNico Weber #include "sanitizer_common/sanitizer_flag_parser.h"
31e2d0b44aSMatt Morehouse #include "sanitizer_common/sanitizer_flags.h"
32e2d0b44aSMatt Morehouse #include "sanitizer_common/sanitizer_internal_defs.h"
33a9aa8137SNico Weber #include "sanitizer_common/sanitizer_libc.h"
34c20db7eaSJianzhou Zhao #include "sanitizer_common/sanitizer_report_decorator.h"
353597fba4SJianzhou Zhao #include "sanitizer_common/sanitizer_stacktrace.h"
3662ed009cSThurston Dang #if SANITIZER_LINUX
3762ed009cSThurston Dang #  include <sys/personality.h>
3862ed009cSThurston Dang #endif
39a9aa8137SNico Weber 
40a9aa8137SNico Weber using namespace __dfsan;
41a9aa8137SNico Weber 
42a9aa8137SNico Weber Flags __dfsan::flags_data;
43a9aa8137SNico Weber 
4480e326a8SJianzhou Zhao // The size of TLS variables. These constants must be kept in sync with the ones
4580e326a8SJianzhou Zhao // in DataFlowSanitizer.cpp.
4680e326a8SJianzhou Zhao static const int kDFsanArgTlsSize = 800;
4780e326a8SJianzhou Zhao static const int kDFsanRetvalTlsSize = 800;
48063a6fa8SJianzhou Zhao static const int kDFsanArgOriginTlsSize = 800;
4980e326a8SJianzhou Zhao 
5080e326a8SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64
5180e326a8SJianzhou Zhao     __dfsan_retval_tls[kDFsanRetvalTlsSize / sizeof(u64)];
52063a6fa8SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __dfsan_retval_origin_tls;
5380e326a8SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64
5480e326a8SJianzhou Zhao     __dfsan_arg_tls[kDFsanArgTlsSize / sizeof(u64)];
55063a6fa8SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32
56063a6fa8SJianzhou Zhao     __dfsan_arg_origin_tls[kDFsanArgOriginTlsSize / sizeof(u32)];
57a9aa8137SNico Weber 
58063a6fa8SJianzhou Zhao // Instrumented code may set this value in terms of -dfsan-track-origins.
59063a6fa8SJianzhou Zhao // * undefined or 0: do not track origins.
60063a6fa8SJianzhou Zhao // * 1: track origins at memory store operations.
61ae6648ceSJianzhou Zhao // * 2: track origins at memory load and store operations.
62ae6648ceSJianzhou Zhao //      TODO: track callsites.
63063a6fa8SJianzhou Zhao extern "C" SANITIZER_WEAK_ATTRIBUTE const int __dfsan_track_origins;
64063a6fa8SJianzhou Zhao 
65ae6648ceSJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE int dfsan_get_track_origins() {
66063a6fa8SJianzhou Zhao   return &__dfsan_track_origins ? __dfsan_track_origins : 0;
67063a6fa8SJianzhou Zhao }
68063a6fa8SJianzhou Zhao 
69a9aa8137SNico Weber // On Linux/x86_64, memory is laid out as follows:
70a9aa8137SNico Weber //
71a9aa8137SNico Weber //  +--------------------+ 0x800000000000 (top of memory)
7245f6d552SAndrew Browne //  |    application 3   |
7345f6d552SAndrew Browne //  +--------------------+ 0x700000000000
7445f6d552SAndrew Browne //  |      invalid       |
7545f6d552SAndrew Browne //  +--------------------+ 0x610000000000
7645f6d552SAndrew Browne //  |      origin 1      |
7745f6d552SAndrew Browne //  +--------------------+ 0x600000000000
7845f6d552SAndrew Browne //  |    application 2   |
7945f6d552SAndrew Browne //  +--------------------+ 0x510000000000
8045f6d552SAndrew Browne //  |      shadow 1      |
8145f6d552SAndrew Browne //  +--------------------+ 0x500000000000
8245f6d552SAndrew Browne //  |      invalid       |
8345f6d552SAndrew Browne //  +--------------------+ 0x400000000000
8445f6d552SAndrew Browne //  |      origin 3      |
8545f6d552SAndrew Browne //  +--------------------+ 0x300000000000
8645f6d552SAndrew Browne //  |      shadow 3      |
875b4dda55SGeorge Balatsouras //  +--------------------+ 0x200000000000
8845f6d552SAndrew Browne //  |      origin 2      |
8945f6d552SAndrew Browne //  +--------------------+ 0x110000000000
9045f6d552SAndrew Browne //  |      invalid       |
9145f6d552SAndrew Browne //  +--------------------+ 0x100000000000
9245f6d552SAndrew Browne //  |      shadow 2      |
9345f6d552SAndrew Browne //  +--------------------+ 0x010000000000
9445f6d552SAndrew Browne //  |    application 1   |
95a9aa8137SNico Weber //  +--------------------+ 0x000000000000
96a9aa8137SNico Weber //
9745f6d552SAndrew Browne //  MEM_TO_SHADOW(mem) = mem ^ 0x500000000000
9845f6d552SAndrew Browne //  SHADOW_TO_ORIGIN(shadow) = shadow + 0x100000000000
99a9aa8137SNico Weber 
100a9aa8137SNico Weber extern "C" SANITIZER_INTERFACE_ATTRIBUTE
101a9aa8137SNico Weber dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {
102a9aa8137SNico Weber   dfsan_label label = ls[0];
103e2d0b44aSMatt Morehouse   for (uptr i = 1; i != n; ++i)
104e2d0b44aSMatt Morehouse     label |= ls[i];
105e2d0b44aSMatt Morehouse   return label;
106e2d0b44aSMatt Morehouse }
107e2d0b44aSMatt Morehouse 
108063a6fa8SJianzhou Zhao // Return the union of all the n labels from addr at the high 32 bit, and the
109063a6fa8SJianzhou Zhao // origin of the first taint byte at the low 32 bit.
110063a6fa8SJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64
111063a6fa8SJianzhou Zhao __dfsan_load_label_and_origin(const void *addr, uptr n) {
112063a6fa8SJianzhou Zhao   dfsan_label label = 0;
113063a6fa8SJianzhou Zhao   u64 ret = 0;
114063a6fa8SJianzhou Zhao   uptr p = (uptr)addr;
115063a6fa8SJianzhou Zhao   dfsan_label *s = shadow_for((void *)p);
116063a6fa8SJianzhou Zhao   for (uptr i = 0; i < n; ++i) {
117063a6fa8SJianzhou Zhao     dfsan_label l = s[i];
118063a6fa8SJianzhou Zhao     if (!l)
119063a6fa8SJianzhou Zhao       continue;
120063a6fa8SJianzhou Zhao     label |= l;
121063a6fa8SJianzhou Zhao     if (!ret)
122063a6fa8SJianzhou Zhao       ret = *(dfsan_origin *)origin_for((void *)(p + i));
123063a6fa8SJianzhou Zhao   }
124063a6fa8SJianzhou Zhao   return ret | (u64)label << 32;
125063a6fa8SJianzhou Zhao }
126063a6fa8SJianzhou Zhao 
127e2d0b44aSMatt Morehouse extern "C" SANITIZER_INTERFACE_ATTRIBUTE
128a9aa8137SNico Weber void __dfsan_unimplemented(char *fname) {
129a9aa8137SNico Weber   if (flags().warn_unimplemented)
130a9aa8137SNico Weber     Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",
131a9aa8137SNico Weber            fname);
132a9aa8137SNico Weber }
133a9aa8137SNico Weber 
134204c12eeSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_wrapper_extern_weak_null(
135204c12eeSAndrew Browne     const void *addr, char *fname) {
136204c12eeSAndrew Browne   if (!addr)
137204c12eeSAndrew Browne     Report(
138204c12eeSAndrew Browne         "ERROR: DataFlowSanitizer: dfsan generated wrapper calling null "
139204c12eeSAndrew Browne         "extern_weak function %s\nIf this only happens with dfsan, the "
140204c12eeSAndrew Browne         "dfsan instrumentation pass may be accidentally optimizing out a "
141204c12eeSAndrew Browne         "null check\n",
142204c12eeSAndrew Browne         fname);
143204c12eeSAndrew Browne }
144204c12eeSAndrew Browne 
145a9aa8137SNico Weber // Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function
146a9aa8137SNico Weber // to try to figure out where labels are being introduced in a nominally
147a9aa8137SNico Weber // label-free program.
148a9aa8137SNico Weber extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
149a9aa8137SNico Weber   if (flags().warn_nonzero_labels)
150a9aa8137SNico Weber     Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
151a9aa8137SNico Weber }
152a9aa8137SNico Weber 
153a9aa8137SNico Weber // Indirect call to an uninstrumented vararg function. We don't have a way of
154a9aa8137SNico Weber // handling these at the moment.
155a9aa8137SNico Weber extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
156a9aa8137SNico Weber __dfsan_vararg_wrapper(const char *fname) {
157a9aa8137SNico Weber   Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
158a9aa8137SNico Weber          "function %s\n", fname);
159a9aa8137SNico Weber   Die();
160a9aa8137SNico Weber }
161a9aa8137SNico Weber 
1625b4dda55SGeorge Balatsouras // Resolves the union of two labels.
163a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
164a9aa8137SNico Weber dfsan_union(dfsan_label l1, dfsan_label l2) {
1655b4dda55SGeorge Balatsouras   return l1 | l2;
166a9aa8137SNico Weber }
167a9aa8137SNico Weber 
168759e7977SAndrew Browne static const uptr kOriginAlign = sizeof(dfsan_origin);
169759e7977SAndrew Browne static const uptr kOriginAlignMask = ~(kOriginAlign - 1UL);
170759e7977SAndrew Browne 
171759e7977SAndrew Browne static uptr OriginAlignUp(uptr u) {
172759e7977SAndrew Browne   return (u + kOriginAlign - 1) & kOriginAlignMask;
173759e7977SAndrew Browne }
174759e7977SAndrew Browne 
175759e7977SAndrew Browne static uptr OriginAlignDown(uptr u) { return u & kOriginAlignMask; }
176759e7977SAndrew Browne 
177063a6fa8SJianzhou Zhao // Return the origin of the first taint byte in the size bytes from the address
178063a6fa8SJianzhou Zhao // addr.
179063a6fa8SJianzhou Zhao static dfsan_origin GetOriginIfTainted(uptr addr, uptr size) {
180063a6fa8SJianzhou Zhao   for (uptr i = 0; i < size; ++i, ++addr) {
181063a6fa8SJianzhou Zhao     dfsan_label *s = shadow_for((void *)addr);
18245f6d552SAndrew Browne 
18345f6d552SAndrew Browne     if (*s) {
18445f6d552SAndrew Browne       // Validate address region.
18545f6d552SAndrew Browne       CHECK(MEM_IS_SHADOW(s));
186063a6fa8SJianzhou Zhao       return *(dfsan_origin *)origin_for((void *)addr);
187063a6fa8SJianzhou Zhao     }
18845f6d552SAndrew Browne   }
189063a6fa8SJianzhou Zhao   return 0;
190063a6fa8SJianzhou Zhao }
191063a6fa8SJianzhou Zhao 
1922d9c6e10SJianzhou Zhao // For platforms which support slow unwinder only, we need to restrict the store
1932d9c6e10SJianzhou Zhao // context size to 1, basically only storing the current pc, because the slow
1942d9c6e10SJianzhou Zhao // unwinder which is based on libunwind is not async signal safe and causes
1952d9c6e10SJianzhou Zhao // random freezes in forking applications as well as in signal handlers.
1962d9c6e10SJianzhou Zhao // DFSan supports only Linux. So we do not restrict the store context size.
1972d9c6e10SJianzhou Zhao #define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
1984cad17deSFlorian Mayer   UNINITIALIZED BufferedStackTrace stack;                 \
1992d9c6e10SJianzhou Zhao   stack.Unwind(pc, bp, nullptr, true, flags().store_context_size);
2002d9c6e10SJianzhou Zhao 
2012d9c6e10SJianzhou Zhao #define PRINT_CALLER_STACK_TRACE        \
2022d9c6e10SJianzhou Zhao   {                                     \
20339b8a271SFangrui Song     GET_CALLER_PC_BP;                   \
2042d9c6e10SJianzhou Zhao     GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
2052d9c6e10SJianzhou Zhao     stack.Print();                      \
2062d9c6e10SJianzhou Zhao   }
2072d9c6e10SJianzhou Zhao 
208063a6fa8SJianzhou Zhao // Return a chain with the previous ID id and the current stack.
209063a6fa8SJianzhou Zhao // from_init = true if this is the first chain of an origin tracking path.
2102d9c6e10SJianzhou Zhao static u32 ChainOrigin(u32 id, StackTrace *stack, bool from_init = false) {
2112d9c6e10SJianzhou Zhao   // StackDepot is not async signal safe. Do not create new chains in a signal
2122d9c6e10SJianzhou Zhao   // handler.
2132d9c6e10SJianzhou Zhao   DFsanThread *t = GetCurrentThread();
2142d9c6e10SJianzhou Zhao   if (t && t->InSignalHandler())
2152d9c6e10SJianzhou Zhao     return id;
2162d9c6e10SJianzhou Zhao 
2172d9c6e10SJianzhou Zhao   // As an optimization the origin of an application byte is updated only when
2182d9c6e10SJianzhou Zhao   // its shadow is non-zero. Because we are only interested in the origins of
2192d9c6e10SJianzhou Zhao   // taint labels, it does not matter what origin a zero label has. This reduces
2202d9c6e10SJianzhou Zhao   // memory write cost. MSan does similar optimization. The following invariant
2212d9c6e10SJianzhou Zhao   // may not hold because of some bugs. We check the invariant to help debug.
2222d9c6e10SJianzhou Zhao   if (!from_init && id == 0 && flags().check_origin_invariant) {
2232d9c6e10SJianzhou Zhao     Printf("  DFSan found invalid origin invariant\n");
2242d9c6e10SJianzhou Zhao     PRINT_CALLER_STACK_TRACE
2252d9c6e10SJianzhou Zhao   }
2262d9c6e10SJianzhou Zhao 
2272d9c6e10SJianzhou Zhao   Origin o = Origin::FromRawId(id);
2282d9c6e10SJianzhou Zhao   stack->tag = StackTrace::TAG_UNKNOWN;
2292d9c6e10SJianzhou Zhao   Origin chained = Origin::CreateChainedOrigin(o, stack);
2302d9c6e10SJianzhou Zhao   return chained.raw_id();
2312d9c6e10SJianzhou Zhao }
232063a6fa8SJianzhou Zhao 
233063a6fa8SJianzhou Zhao static void ChainAndWriteOriginIfTainted(uptr src, uptr size, uptr dst,
234063a6fa8SJianzhou Zhao                                          StackTrace *stack) {
235063a6fa8SJianzhou Zhao   dfsan_origin o = GetOriginIfTainted(src, size);
236063a6fa8SJianzhou Zhao   if (o) {
237063a6fa8SJianzhou Zhao     o = ChainOrigin(o, stack);
238063a6fa8SJianzhou Zhao     *(dfsan_origin *)origin_for((void *)dst) = o;
239063a6fa8SJianzhou Zhao   }
240063a6fa8SJianzhou Zhao }
241063a6fa8SJianzhou Zhao 
242063a6fa8SJianzhou Zhao // Copy the origins of the size bytes from src to dst. The source and target
243063a6fa8SJianzhou Zhao // memory ranges cannot be overlapped. This is used by memcpy. stack records the
244063a6fa8SJianzhou Zhao // stack trace of the memcpy. When dst and src are not 4-byte aligned properly,
245063a6fa8SJianzhou Zhao // origins at the unaligned address boundaries may be overwritten because four
246063a6fa8SJianzhou Zhao // contiguous bytes share the same origin.
247063a6fa8SJianzhou Zhao static void CopyOrigin(const void *dst, const void *src, uptr size,
248063a6fa8SJianzhou Zhao                        StackTrace *stack) {
249063a6fa8SJianzhou Zhao   uptr d = (uptr)dst;
250759e7977SAndrew Browne   uptr beg = OriginAlignDown(d);
251063a6fa8SJianzhou Zhao   // Copy left unaligned origin if that memory is tainted.
252063a6fa8SJianzhou Zhao   if (beg < d) {
253063a6fa8SJianzhou Zhao     ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);
254063a6fa8SJianzhou Zhao     beg += kOriginAlign;
255063a6fa8SJianzhou Zhao   }
256063a6fa8SJianzhou Zhao 
257759e7977SAndrew Browne   uptr end = OriginAlignDown(d + size);
258063a6fa8SJianzhou Zhao   // If both ends fall into the same 4-byte slot, we are done.
259063a6fa8SJianzhou Zhao   if (end < beg)
260063a6fa8SJianzhou Zhao     return;
261063a6fa8SJianzhou Zhao 
262063a6fa8SJianzhou Zhao   // Copy right unaligned origin if that memory is tainted.
263063a6fa8SJianzhou Zhao   if (end < d + size)
264063a6fa8SJianzhou Zhao     ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,
265063a6fa8SJianzhou Zhao                                  stack);
266063a6fa8SJianzhou Zhao 
267063a6fa8SJianzhou Zhao   if (beg >= end)
268063a6fa8SJianzhou Zhao     return;
269063a6fa8SJianzhou Zhao 
270063a6fa8SJianzhou Zhao   // Align src up.
271759e7977SAndrew Browne   uptr src_a = OriginAlignUp((uptr)src);
272759e7977SAndrew Browne   dfsan_origin *src_o = origin_for((void *)src_a);
273759e7977SAndrew Browne   u32 *src_s = (u32 *)shadow_for((void *)src_a);
274759e7977SAndrew Browne   dfsan_origin *src_end = origin_for((void *)(src_a + (end - beg)));
275759e7977SAndrew Browne   dfsan_origin *dst_o = origin_for((void *)beg);
276063a6fa8SJianzhou Zhao   dfsan_origin last_src_o = 0;
277063a6fa8SJianzhou Zhao   dfsan_origin last_dst_o = 0;
278063a6fa8SJianzhou Zhao   for (; src_o < src_end; ++src_o, ++src_s, ++dst_o) {
279063a6fa8SJianzhou Zhao     if (!*src_s)
280063a6fa8SJianzhou Zhao       continue;
281063a6fa8SJianzhou Zhao     if (*src_o != last_src_o) {
282063a6fa8SJianzhou Zhao       last_src_o = *src_o;
283063a6fa8SJianzhou Zhao       last_dst_o = ChainOrigin(last_src_o, stack);
284063a6fa8SJianzhou Zhao     }
285063a6fa8SJianzhou Zhao     *dst_o = last_dst_o;
286063a6fa8SJianzhou Zhao   }
287063a6fa8SJianzhou Zhao }
288063a6fa8SJianzhou Zhao 
289063a6fa8SJianzhou Zhao // Copy the origins of the size bytes from src to dst. The source and target
290063a6fa8SJianzhou Zhao // memory ranges may be overlapped. So the copy is done in a reverse order.
291063a6fa8SJianzhou Zhao // This is used by memmove. stack records the stack trace of the memmove.
292063a6fa8SJianzhou Zhao static void ReverseCopyOrigin(const void *dst, const void *src, uptr size,
293063a6fa8SJianzhou Zhao                               StackTrace *stack) {
294063a6fa8SJianzhou Zhao   uptr d = (uptr)dst;
295759e7977SAndrew Browne   uptr end = OriginAlignDown(d + size);
296063a6fa8SJianzhou Zhao 
297063a6fa8SJianzhou Zhao   // Copy right unaligned origin if that memory is tainted.
298063a6fa8SJianzhou Zhao   if (end < d + size)
299063a6fa8SJianzhou Zhao     ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,
300063a6fa8SJianzhou Zhao                                  stack);
301063a6fa8SJianzhou Zhao 
302759e7977SAndrew Browne   uptr beg = OriginAlignDown(d);
303063a6fa8SJianzhou Zhao 
304063a6fa8SJianzhou Zhao   if (beg + kOriginAlign < end) {
305063a6fa8SJianzhou Zhao     // Align src up.
306759e7977SAndrew Browne     uptr src_a = OriginAlignUp((uptr)src);
307759e7977SAndrew Browne     void *src_end = (void *)(src_a + end - beg - kOriginAlign);
308759e7977SAndrew Browne     dfsan_origin *src_end_o = origin_for(src_end);
309759e7977SAndrew Browne     u32 *src_end_s = (u32 *)shadow_for(src_end);
310759e7977SAndrew Browne     dfsan_origin *src_begin_o = origin_for((void *)src_a);
311759e7977SAndrew Browne     dfsan_origin *dst = origin_for((void *)(end - kOriginAlign));
312759e7977SAndrew Browne     dfsan_origin last_src_o = 0;
313759e7977SAndrew Browne     dfsan_origin last_dst_o = 0;
314759e7977SAndrew Browne     for (; src_end_o >= src_begin_o; --src_end_o, --src_end_s, --dst) {
315759e7977SAndrew Browne       if (!*src_end_s)
316063a6fa8SJianzhou Zhao         continue;
317759e7977SAndrew Browne       if (*src_end_o != last_src_o) {
318759e7977SAndrew Browne         last_src_o = *src_end_o;
319759e7977SAndrew Browne         last_dst_o = ChainOrigin(last_src_o, stack);
320063a6fa8SJianzhou Zhao       }
321759e7977SAndrew Browne       *dst = last_dst_o;
322063a6fa8SJianzhou Zhao     }
323063a6fa8SJianzhou Zhao   }
324063a6fa8SJianzhou Zhao 
325063a6fa8SJianzhou Zhao   // Copy left unaligned origin if that memory is tainted.
326063a6fa8SJianzhou Zhao   if (beg < d)
327063a6fa8SJianzhou Zhao     ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);
328063a6fa8SJianzhou Zhao }
329063a6fa8SJianzhou Zhao 
330063a6fa8SJianzhou Zhao // Copy or move the origins of the len bytes from src to dst. The source and
331063a6fa8SJianzhou Zhao // target memory ranges may or may not be overlapped. This is used by memory
332063a6fa8SJianzhou Zhao // transfer operations. stack records the stack trace of the memory transfer
333063a6fa8SJianzhou Zhao // operation.
334063a6fa8SJianzhou Zhao static void MoveOrigin(const void *dst, const void *src, uptr size,
335063a6fa8SJianzhou Zhao                        StackTrace *stack) {
33645f6d552SAndrew Browne   // Validate address regions.
33745f6d552SAndrew Browne   if (!MEM_IS_SHADOW(shadow_for(dst)) ||
33845f6d552SAndrew Browne       !MEM_IS_SHADOW(shadow_for((void *)((uptr)dst + size))) ||
33945f6d552SAndrew Browne       !MEM_IS_SHADOW(shadow_for(src)) ||
34045f6d552SAndrew Browne       !MEM_IS_SHADOW(shadow_for((void *)((uptr)src + size)))) {
34145f6d552SAndrew Browne     CHECK(false);
342063a6fa8SJianzhou Zhao     return;
343063a6fa8SJianzhou Zhao   }
344063a6fa8SJianzhou Zhao   // If destination origin range overlaps with source origin range, move
345063a6fa8SJianzhou Zhao   // origins by copying origins in a reverse order; otherwise, copy origins in
346063a6fa8SJianzhou Zhao   // a normal order. The orders of origin transfer are consistent with the
347063a6fa8SJianzhou Zhao   // orders of how memcpy and memmove transfer user data.
3487607ddd9SAndrew Browne   uptr src_aligned_beg = OriginAlignDown((uptr)src);
3497607ddd9SAndrew Browne   uptr src_aligned_end = OriginAlignDown((uptr)src + size);
3507607ddd9SAndrew Browne   uptr dst_aligned_beg = OriginAlignDown((uptr)dst);
351063a6fa8SJianzhou Zhao   if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)
352063a6fa8SJianzhou Zhao     return ReverseCopyOrigin(dst, src, size, stack);
353063a6fa8SJianzhou Zhao   return CopyOrigin(dst, src, size, stack);
354063a6fa8SJianzhou Zhao }
355063a6fa8SJianzhou Zhao 
356063a6fa8SJianzhou Zhao // Set the size bytes from the addres dst to be the origin value.
357063a6fa8SJianzhou Zhao static void SetOrigin(const void *dst, uptr size, u32 origin) {
358063a6fa8SJianzhou Zhao   if (size == 0)
359063a6fa8SJianzhou Zhao     return;
360063a6fa8SJianzhou Zhao 
361063a6fa8SJianzhou Zhao   // Origin mapping is 4 bytes per 4 bytes of application memory.
362063a6fa8SJianzhou Zhao   // Here we extend the range such that its left and right bounds are both
363063a6fa8SJianzhou Zhao   // 4 byte aligned.
364063a6fa8SJianzhou Zhao   uptr x = unaligned_origin_for((uptr)dst);
365759e7977SAndrew Browne   uptr beg = OriginAlignDown(x);
366759e7977SAndrew Browne   uptr end = OriginAlignUp(x + size);  // align up.
367063a6fa8SJianzhou Zhao   u64 origin64 = ((u64)origin << 32) | origin;
368063a6fa8SJianzhou Zhao   // This is like memset, but the value is 32-bit. We unroll by 2 to write
369063a6fa8SJianzhou Zhao   // 64 bits at once. May want to unroll further to get 128-bit stores.
370063a6fa8SJianzhou Zhao   if (beg & 7ULL) {
371063a6fa8SJianzhou Zhao     if (*(u32 *)beg != origin)
372063a6fa8SJianzhou Zhao       *(u32 *)beg = origin;
373063a6fa8SJianzhou Zhao     beg += 4;
374063a6fa8SJianzhou Zhao   }
375063a6fa8SJianzhou Zhao   for (uptr addr = beg; addr < (end & ~7UL); addr += 8) {
376063a6fa8SJianzhou Zhao     if (*(u64 *)addr == origin64)
377063a6fa8SJianzhou Zhao       continue;
378063a6fa8SJianzhou Zhao     *(u64 *)addr = origin64;
379063a6fa8SJianzhou Zhao   }
380063a6fa8SJianzhou Zhao   if (end & 7ULL)
381063a6fa8SJianzhou Zhao     if (*(u32 *)(end - kOriginAlign) != origin)
382063a6fa8SJianzhou Zhao       *(u32 *)(end - kOriginAlign) = origin;
383063a6fa8SJianzhou Zhao }
3842d9c6e10SJianzhou Zhao 
3857fdf2709SJianzhou Zhao #define RET_CHAIN_ORIGIN(id)           \
38639b8a271SFangrui Song   GET_CALLER_PC_BP;                    \
3877fdf2709SJianzhou Zhao   GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
3887fdf2709SJianzhou Zhao   return ChainOrigin(id, &stack);
3897fdf2709SJianzhou Zhao 
390063a6fa8SJianzhou Zhao // Return a new origin chain with the previous ID id and the current stack
391063a6fa8SJianzhou Zhao // trace.
392063a6fa8SJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
393063a6fa8SJianzhou Zhao __dfsan_chain_origin(dfsan_origin id) {
3947fdf2709SJianzhou Zhao   RET_CHAIN_ORIGIN(id)
3957fdf2709SJianzhou Zhao }
3967fdf2709SJianzhou Zhao 
3977fdf2709SJianzhou Zhao // Return a new origin chain with the previous ID id and the current stack
3987fdf2709SJianzhou Zhao // trace if the label is tainted.
3997fdf2709SJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
4007fdf2709SJianzhou Zhao __dfsan_chain_origin_if_tainted(dfsan_label label, dfsan_origin id) {
4017fdf2709SJianzhou Zhao   if (!label)
4027fdf2709SJianzhou Zhao     return id;
4037fdf2709SJianzhou Zhao   RET_CHAIN_ORIGIN(id)
404063a6fa8SJianzhou Zhao }
405063a6fa8SJianzhou Zhao 
406063a6fa8SJianzhou Zhao // Copy or move the origins of the len bytes from src to dst.
407063a6fa8SJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_mem_origin_transfer(
408063a6fa8SJianzhou Zhao     const void *dst, const void *src, uptr len) {
409063a6fa8SJianzhou Zhao   if (src == dst)
410063a6fa8SJianzhou Zhao     return;
411063a6fa8SJianzhou Zhao   GET_CALLER_PC_BP;
412063a6fa8SJianzhou Zhao   GET_STORE_STACK_TRACE_PC_BP(pc, bp);
413063a6fa8SJianzhou Zhao   MoveOrigin(dst, src, len, &stack);
414063a6fa8SJianzhou Zhao }
415063a6fa8SJianzhou Zhao 
41632167bfeSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_origin_transfer(
41732167bfeSAndrew Browne     const void *dst, const void *src, uptr len) {
418063a6fa8SJianzhou Zhao   __dfsan_mem_origin_transfer(dst, src, len);
419063a6fa8SJianzhou Zhao }
420063a6fa8SJianzhou Zhao 
421065d2e1dSAndrew Browne static void CopyShadow(void *dst, const void *src, uptr len) {
42232167bfeSAndrew Browne   internal_memcpy((void *)__dfsan::shadow_for(dst),
42332167bfeSAndrew Browne                   (const void *)__dfsan::shadow_for(src),
42432167bfeSAndrew Browne                   len * sizeof(dfsan_label));
42532167bfeSAndrew Browne }
42632167bfeSAndrew Browne 
427065d2e1dSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_shadow_transfer(
428065d2e1dSAndrew Browne     void *dst, const void *src, uptr len) {
429065d2e1dSAndrew Browne   CopyShadow(dst, src, len);
430065d2e1dSAndrew Browne }
431065d2e1dSAndrew Browne 
432065d2e1dSAndrew Browne // Copy shadow and origins of the len bytes from src to dst.
433065d2e1dSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
434065d2e1dSAndrew Browne __dfsan_mem_shadow_origin_transfer(void *dst, const void *src, uptr size) {
435065d2e1dSAndrew Browne   if (src == dst)
436065d2e1dSAndrew Browne     return;
437065d2e1dSAndrew Browne   CopyShadow(dst, src, size);
438065d2e1dSAndrew Browne   if (dfsan_get_track_origins()) {
439065d2e1dSAndrew Browne     // Duplicating code instead of calling __dfsan_mem_origin_transfer
440065d2e1dSAndrew Browne     // so that the getting the caller stack frame works correctly.
441065d2e1dSAndrew Browne     GET_CALLER_PC_BP;
442065d2e1dSAndrew Browne     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
443065d2e1dSAndrew Browne     MoveOrigin(dst, src, size, &stack);
444065d2e1dSAndrew Browne   }
445065d2e1dSAndrew Browne }
446065d2e1dSAndrew Browne 
447065d2e1dSAndrew Browne // Copy shadow and origins as per __atomic_compare_exchange.
448065d2e1dSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
449065d2e1dSAndrew Browne __dfsan_mem_shadow_origin_conditional_exchange(u8 condition, void *target,
450065d2e1dSAndrew Browne                                                void *expected,
451065d2e1dSAndrew Browne                                                const void *desired, uptr size) {
452065d2e1dSAndrew Browne   void *dst;
453065d2e1dSAndrew Browne   const void *src;
454065d2e1dSAndrew Browne   // condition is result of native call to __atomic_compare_exchange
455065d2e1dSAndrew Browne   if (condition) {
456065d2e1dSAndrew Browne     // Copy desired into target
457065d2e1dSAndrew Browne     dst = target;
458065d2e1dSAndrew Browne     src = desired;
459065d2e1dSAndrew Browne   } else {
460065d2e1dSAndrew Browne     // Copy target into expected
461065d2e1dSAndrew Browne     dst = expected;
462065d2e1dSAndrew Browne     src = target;
463065d2e1dSAndrew Browne   }
464065d2e1dSAndrew Browne   if (src == dst)
465065d2e1dSAndrew Browne     return;
466065d2e1dSAndrew Browne   CopyShadow(dst, src, size);
467065d2e1dSAndrew Browne   if (dfsan_get_track_origins()) {
468065d2e1dSAndrew Browne     // Duplicating code instead of calling __dfsan_mem_origin_transfer
469065d2e1dSAndrew Browne     // so that the getting the caller stack frame works correctly.
470065d2e1dSAndrew Browne     GET_CALLER_PC_BP;
471065d2e1dSAndrew Browne     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
472065d2e1dSAndrew Browne     MoveOrigin(dst, src, size, &stack);
473065d2e1dSAndrew Browne   }
474065d2e1dSAndrew Browne }
475065d2e1dSAndrew Browne 
476fe31363aSFangrui Song bool __dfsan::dfsan_inited;
477fe31363aSFangrui Song bool __dfsan::dfsan_init_is_running;
4781fb612d0SJianzhou Zhao 
479fe31363aSFangrui Song void __dfsan::dfsan_copy_memory(void *dst, const void *src, uptr size) {
4801fb612d0SJianzhou Zhao   internal_memcpy(dst, src, size);
48132167bfeSAndrew Browne   dfsan_mem_shadow_transfer(dst, src, size);
482ae6648ceSJianzhou Zhao   if (dfsan_get_track_origins())
4831fb612d0SJianzhou Zhao     dfsan_mem_origin_transfer(dst, src, size);
4841fb612d0SJianzhou Zhao }
4851fb612d0SJianzhou Zhao 
4861fb612d0SJianzhou Zhao // Releases the pages within the origin address range.
4871fb612d0SJianzhou Zhao static void ReleaseOrigins(void *addr, uptr size) {
488a05aa0ddSJianzhou Zhao   const uptr beg_origin_addr = (uptr)__dfsan::origin_for(addr);
489a05aa0ddSJianzhou Zhao   const void *end_addr = (void *)((uptr)addr + size);
490a05aa0ddSJianzhou Zhao   const uptr end_origin_addr = (uptr)__dfsan::origin_for(end_addr);
4911fb612d0SJianzhou Zhao 
4921fb612d0SJianzhou Zhao   if (end_origin_addr - beg_origin_addr <
4931fb612d0SJianzhou Zhao       common_flags()->clear_shadow_mmap_threshold)
4941fb612d0SJianzhou Zhao     return;
4951fb612d0SJianzhou Zhao 
496a05aa0ddSJianzhou Zhao   const uptr page_size = GetPageSizeCached();
497a05aa0ddSJianzhou Zhao   const uptr beg_aligned = RoundUpTo(beg_origin_addr, page_size);
498a05aa0ddSJianzhou Zhao   const uptr end_aligned = RoundDownTo(end_origin_addr, page_size);
499a05aa0ddSJianzhou Zhao 
5001fb612d0SJianzhou Zhao   if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
5011fb612d0SJianzhou Zhao     Die();
5021fb612d0SJianzhou Zhao }
503a05aa0ddSJianzhou Zhao 
504d81723c9SAndrew Browne static void WriteZeroShadowInRange(uptr beg, uptr end) {
505d81723c9SAndrew Browne   // Don't write the label if it is already the value we need it to be.
506d81723c9SAndrew Browne   // In a program where most addresses are not labeled, it is common that
507d81723c9SAndrew Browne   // a page of shadow memory is entirely zeroed.  The Linux copy-on-write
508d81723c9SAndrew Browne   // implementation will share all of the zeroed pages, making a copy of a
509d81723c9SAndrew Browne   // page when any value is written.  The un-sharing will happen even if
510d81723c9SAndrew Browne   // the value written does not change the value in memory.  Avoiding the
511d81723c9SAndrew Browne   // write when both |label| and |*labelp| are zero dramatically reduces
512d81723c9SAndrew Browne   // the amount of real memory used by large programs.
513d81723c9SAndrew Browne   if (!mem_is_zero((const char *)beg, end - beg))
514d81723c9SAndrew Browne     internal_memset((void *)beg, 0, end - beg);
515d81723c9SAndrew Browne }
516d81723c9SAndrew Browne 
5171fb612d0SJianzhou Zhao // Releases the pages within the shadow address range, and sets
5181fb612d0SJianzhou Zhao // the shadow addresses not on the pages to be 0.
5191fb612d0SJianzhou Zhao static void ReleaseOrClearShadows(void *addr, uptr size) {
5201fb612d0SJianzhou Zhao   const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
5211fb612d0SJianzhou Zhao   const void *end_addr = (void *)((uptr)addr + size);
5221fb612d0SJianzhou Zhao   const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr);
5231fb612d0SJianzhou Zhao 
5241fb612d0SJianzhou Zhao   if (end_shadow_addr - beg_shadow_addr <
525d81723c9SAndrew Browne       common_flags()->clear_shadow_mmap_threshold) {
526d81723c9SAndrew Browne     WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
527d81723c9SAndrew Browne     return;
528d81723c9SAndrew Browne   }
5291fb612d0SJianzhou Zhao 
5301fb612d0SJianzhou Zhao   const uptr page_size = GetPageSizeCached();
5311fb612d0SJianzhou Zhao   const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size);
5321fb612d0SJianzhou Zhao   const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size);
5331fb612d0SJianzhou Zhao 
5341fb612d0SJianzhou Zhao   if (beg_aligned >= end_aligned) {
535d81723c9SAndrew Browne     WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
5361fb612d0SJianzhou Zhao   } else {
5371fb612d0SJianzhou Zhao     if (beg_aligned != beg_shadow_addr)
538d81723c9SAndrew Browne       WriteZeroShadowInRange(beg_shadow_addr, beg_aligned);
5391fb612d0SJianzhou Zhao     if (end_aligned != end_shadow_addr)
540d81723c9SAndrew Browne       WriteZeroShadowInRange(end_aligned, end_shadow_addr);
5411fb612d0SJianzhou Zhao     if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
5421fb612d0SJianzhou Zhao       Die();
5431fb612d0SJianzhou Zhao   }
544a05aa0ddSJianzhou Zhao }
545a05aa0ddSJianzhou Zhao 
546fe31363aSFangrui Song static void SetShadow(dfsan_label label, void *addr, uptr size,
547fe31363aSFangrui Song                       dfsan_origin origin) {
548cc07fbe3SJianzhou Zhao   if (0 != label) {
5491fb612d0SJianzhou Zhao     const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
550d81723c9SAndrew Browne     internal_memset((void *)beg_shadow_addr, label, size);
551ae6648ceSJianzhou Zhao     if (dfsan_get_track_origins())
552a05aa0ddSJianzhou Zhao       SetOrigin(addr, size, origin);
553cc07fbe3SJianzhou Zhao     return;
554cc07fbe3SJianzhou Zhao   }
555cc07fbe3SJianzhou Zhao 
556ae6648ceSJianzhou Zhao   if (dfsan_get_track_origins())
5571fb612d0SJianzhou Zhao     ReleaseOrigins(addr, size);
558a05aa0ddSJianzhou Zhao 
5591fb612d0SJianzhou Zhao   ReleaseOrClearShadows(addr, size);
560cc07fbe3SJianzhou Zhao }
561cc07fbe3SJianzhou Zhao 
562d81723c9SAndrew Browne // If the label s is tainted, set the size bytes from the address p to be a new
563d81723c9SAndrew Browne // origin chain with the previous ID o and the current stack trace. This is
564d81723c9SAndrew Browne // used by instrumentation to reduce code size when too much code is inserted.
565d81723c9SAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin(
566d81723c9SAndrew Browne     dfsan_label s, void *p, uptr size, dfsan_origin o) {
567d81723c9SAndrew Browne   if (UNLIKELY(s)) {
56839b8a271SFangrui Song     GET_CALLER_PC_BP;
569d81723c9SAndrew Browne     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
570d81723c9SAndrew Browne     SetOrigin(p, size, ChainOrigin(o, &stack));
571d81723c9SAndrew Browne   }
572d81723c9SAndrew Browne }
573d81723c9SAndrew Browne 
574a05aa0ddSJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(
575a05aa0ddSJianzhou Zhao     dfsan_label label, dfsan_origin origin, void *addr, uptr size) {
576fe31363aSFangrui Song   SetShadow(label, addr, size, origin);
577a05aa0ddSJianzhou Zhao }
578a05aa0ddSJianzhou Zhao 
579a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
580a9aa8137SNico Weber void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
581a05aa0ddSJianzhou Zhao   dfsan_origin init_origin = 0;
582ae6648ceSJianzhou Zhao   if (label && dfsan_get_track_origins()) {
583a05aa0ddSJianzhou Zhao     GET_CALLER_PC_BP;
584a05aa0ddSJianzhou Zhao     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
585a05aa0ddSJianzhou Zhao     init_origin = ChainOrigin(0, &stack, true);
586a05aa0ddSJianzhou Zhao   }
587fe31363aSFangrui Song   SetShadow(label, addr, size, init_origin);
588a9aa8137SNico Weber }
589a9aa8137SNico Weber 
590a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE
591a9aa8137SNico Weber void dfsan_add_label(dfsan_label label, void *addr, uptr size) {
592a05aa0ddSJianzhou Zhao   if (0 == label)
593a05aa0ddSJianzhou Zhao     return;
594a05aa0ddSJianzhou Zhao 
595ae6648ceSJianzhou Zhao   if (dfsan_get_track_origins()) {
596a05aa0ddSJianzhou Zhao     GET_CALLER_PC_BP;
597a05aa0ddSJianzhou Zhao     GET_STORE_STACK_TRACE_PC_BP(pc, bp);
598a05aa0ddSJianzhou Zhao     dfsan_origin init_origin = ChainOrigin(0, &stack, true);
599a05aa0ddSJianzhou Zhao     SetOrigin(addr, size, init_origin);
600a05aa0ddSJianzhou Zhao   }
601a05aa0ddSJianzhou Zhao 
602a9aa8137SNico Weber   for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
6035b4dda55SGeorge Balatsouras     *labelp |= label;
604a9aa8137SNico Weber }
605a9aa8137SNico Weber 
606a9aa8137SNico Weber // Unlike the other dfsan interface functions the behavior of this function
607a9aa8137SNico Weber // depends on the label of one of its arguments.  Hence it is implemented as a
608a9aa8137SNico Weber // custom function.
609a9aa8137SNico Weber extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
610a9aa8137SNico Weber __dfsw_dfsan_get_label(long data, dfsan_label data_label,
611a9aa8137SNico Weber                        dfsan_label *ret_label) {
612a9aa8137SNico Weber   *ret_label = 0;
613a9aa8137SNico Weber   return data_label;
614a9aa8137SNico Weber }
615a9aa8137SNico Weber 
616c20db7eaSJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfso_dfsan_get_label(
617c20db7eaSJianzhou Zhao     long data, dfsan_label data_label, dfsan_label *ret_label,
618c20db7eaSJianzhou Zhao     dfsan_origin data_origin, dfsan_origin *ret_origin) {
619c20db7eaSJianzhou Zhao   *ret_label = 0;
620c20db7eaSJianzhou Zhao   *ret_origin = 0;
621c20db7eaSJianzhou Zhao   return data_label;
622c20db7eaSJianzhou Zhao }
623c20db7eaSJianzhou Zhao 
6244e67ae7bSJianzhou Zhao // This function is used if dfsan_get_origin is called when origin tracking is
6254e67ae7bSJianzhou Zhao // off.
6264e67ae7bSJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfsw_dfsan_get_origin(
6274e67ae7bSJianzhou Zhao     long data, dfsan_label data_label, dfsan_label *ret_label) {
6284e67ae7bSJianzhou Zhao   *ret_label = 0;
6294e67ae7bSJianzhou Zhao   return 0;
6304e67ae7bSJianzhou Zhao }
6314e67ae7bSJianzhou Zhao 
632c20db7eaSJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfso_dfsan_get_origin(
633c20db7eaSJianzhou Zhao     long data, dfsan_label data_label, dfsan_label *ret_label,
634c20db7eaSJianzhou Zhao     dfsan_origin data_origin, dfsan_origin *ret_origin) {
635c20db7eaSJianzhou Zhao   *ret_label = 0;
636c20db7eaSJianzhou Zhao   *ret_origin = 0;
637c20db7eaSJianzhou Zhao   return data_origin;
638c20db7eaSJianzhou Zhao }
639c20db7eaSJianzhou Zhao 
640a9aa8137SNico Weber SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
641a9aa8137SNico Weber dfsan_read_label(const void *addr, uptr size) {
642a9aa8137SNico Weber   if (size == 0)
643a9aa8137SNico Weber     return 0;
644a9aa8137SNico Weber   return __dfsan_union_load(shadow_for(addr), size);
645a9aa8137SNico Weber }
646a9aa8137SNico Weber 
647063a6fa8SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
648063a6fa8SJianzhou Zhao dfsan_read_origin_of_first_taint(const void *addr, uptr size) {
649063a6fa8SJianzhou Zhao   return GetOriginIfTainted((uptr)addr, size);
650063a6fa8SJianzhou Zhao }
651063a6fa8SJianzhou Zhao 
6521fe04204SJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label_origin(dfsan_label label,
6531fe04204SJianzhou Zhao                                                           dfsan_origin origin,
6541fe04204SJianzhou Zhao                                                           void *addr,
6551fe04204SJianzhou Zhao                                                           uptr size) {
6561fe04204SJianzhou Zhao   __dfsan_set_label(label, origin, addr, size);
6571fe04204SJianzhou Zhao }
6581fe04204SJianzhou Zhao 
659a9aa8137SNico Weber extern "C" SANITIZER_INTERFACE_ATTRIBUTE int
660a9aa8137SNico Weber dfsan_has_label(dfsan_label label, dfsan_label elem) {
6615b4dda55SGeorge Balatsouras   return (label & elem) == elem;
662a9aa8137SNico Weber }
663a9aa8137SNico Weber 
6644e173585SAndrew Browne namespace __dfsan {
6654e173585SAndrew Browne typedef void (*dfsan_conditional_callback_t)(dfsan_label label,
6664e173585SAndrew Browne                                              dfsan_origin origin);
667fe31363aSFangrui Song 
668fe31363aSFangrui Song }  // namespace __dfsan
6694e173585SAndrew Browne static dfsan_conditional_callback_t conditional_callback = nullptr;
6704e173585SAndrew Browne static dfsan_label labels_in_signal_conditional = 0;
6714e173585SAndrew Browne 
6724e173585SAndrew Browne static void ConditionalCallback(dfsan_label label, dfsan_origin origin) {
6734e173585SAndrew Browne   // Programs have many branches. For efficiency the conditional sink callback
6744e173585SAndrew Browne   // handler needs to ignore as many as possible as early as possible.
6754e173585SAndrew Browne   if (label == 0) {
6764e173585SAndrew Browne     return;
6774e173585SAndrew Browne   }
6784e173585SAndrew Browne   if (conditional_callback == nullptr) {
6794e173585SAndrew Browne     return;
6804e173585SAndrew Browne   }
6814e173585SAndrew Browne 
6824e173585SAndrew Browne   // This initial ConditionalCallback handler needs to be in here in dfsan
6834e173585SAndrew Browne   // runtime (rather than being an entirely user implemented hook) so that it
6844e173585SAndrew Browne   // has access to dfsan thread information.
6854e173585SAndrew Browne   DFsanThread *t = GetCurrentThread();
6864e173585SAndrew Browne   // A callback operation which does useful work (like record the flow) will
6874e173585SAndrew Browne   // likely be too long executed in a signal handler.
6884e173585SAndrew Browne   if (t && t->InSignalHandler()) {
6894e173585SAndrew Browne     // Record set of labels used in signal handler for completeness.
6904e173585SAndrew Browne     labels_in_signal_conditional |= label;
6914e173585SAndrew Browne     return;
6924e173585SAndrew Browne   }
6934e173585SAndrew Browne 
6944e173585SAndrew Browne   conditional_callback(label, origin);
6954e173585SAndrew Browne }
6964e173585SAndrew Browne 
6974e173585SAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
6984e173585SAndrew Browne __dfsan_conditional_callback_origin(dfsan_label label, dfsan_origin origin) {
699fe31363aSFangrui Song   ConditionalCallback(label, origin);
7004e173585SAndrew Browne }
7014e173585SAndrew Browne 
7024e173585SAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_conditional_callback(
7034e173585SAndrew Browne     dfsan_label label) {
704fe31363aSFangrui Song   ConditionalCallback(label, 0);
7054e173585SAndrew Browne }
7064e173585SAndrew Browne 
7074e173585SAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_conditional_callback(
7084e173585SAndrew Browne     __dfsan::dfsan_conditional_callback_t callback) {
709fe31363aSFangrui Song   conditional_callback = callback;
7104e173585SAndrew Browne }
7114e173585SAndrew Browne 
7124e173585SAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
7134e173585SAndrew Browne dfsan_get_labels_in_signal_conditional() {
714fe31363aSFangrui Song   return labels_in_signal_conditional;
7154e173585SAndrew Browne }
7164e173585SAndrew Browne 
7175bb06c7cSAndrew Browne namespace __dfsan {
7185bb06c7cSAndrew Browne typedef void (*dfsan_reaches_function_callback_t)(dfsan_label label,
7195bb06c7cSAndrew Browne                                                   dfsan_origin origin,
7205bb06c7cSAndrew Browne                                                   const char *file,
7215bb06c7cSAndrew Browne                                                   unsigned int line,
7225bb06c7cSAndrew Browne                                                   const char *function);
723fe31363aSFangrui Song 
724fe31363aSFangrui Song }  // namespace __dfsan
7255bb06c7cSAndrew Browne static dfsan_reaches_function_callback_t reaches_function_callback = nullptr;
7265bb06c7cSAndrew Browne static dfsan_label labels_in_signal_reaches_function = 0;
7275bb06c7cSAndrew Browne 
7285bb06c7cSAndrew Browne static void ReachesFunctionCallback(dfsan_label label, dfsan_origin origin,
7295bb06c7cSAndrew Browne                                     const char *file, unsigned int line,
7305bb06c7cSAndrew Browne                                     const char *function) {
7315bb06c7cSAndrew Browne   if (label == 0) {
7325bb06c7cSAndrew Browne     return;
7335bb06c7cSAndrew Browne   }
7345bb06c7cSAndrew Browne   if (reaches_function_callback == nullptr) {
7355bb06c7cSAndrew Browne     return;
7365bb06c7cSAndrew Browne   }
7375bb06c7cSAndrew Browne 
7385bb06c7cSAndrew Browne   // This initial ReachesFunctionCallback handler needs to be in here in dfsan
7395bb06c7cSAndrew Browne   // runtime (rather than being an entirely user implemented hook) so that it
7405bb06c7cSAndrew Browne   // has access to dfsan thread information.
7415bb06c7cSAndrew Browne   DFsanThread *t = GetCurrentThread();
7425bb06c7cSAndrew Browne   // A callback operation which does useful work (like record the flow) will
7435bb06c7cSAndrew Browne   // likely be too long executed in a signal handler.
7445bb06c7cSAndrew Browne   if (t && t->InSignalHandler()) {
7455bb06c7cSAndrew Browne     // Record set of labels used in signal handler for completeness.
7465bb06c7cSAndrew Browne     labels_in_signal_reaches_function |= label;
7475bb06c7cSAndrew Browne     return;
7485bb06c7cSAndrew Browne   }
7495bb06c7cSAndrew Browne 
7505bb06c7cSAndrew Browne   reaches_function_callback(label, origin, file, line, function);
7515bb06c7cSAndrew Browne }
7525bb06c7cSAndrew Browne 
7535bb06c7cSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
7545bb06c7cSAndrew Browne __dfsan_reaches_function_callback_origin(dfsan_label label, dfsan_origin origin,
7555bb06c7cSAndrew Browne                                          const char *file, unsigned int line,
7565bb06c7cSAndrew Browne                                          const char *function) {
757fe31363aSFangrui Song   ReachesFunctionCallback(label, origin, file, line, function);
7585bb06c7cSAndrew Browne }
7595bb06c7cSAndrew Browne 
7605bb06c7cSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
7615bb06c7cSAndrew Browne __dfsan_reaches_function_callback(dfsan_label label, const char *file,
7625bb06c7cSAndrew Browne                                   unsigned int line, const char *function) {
763fe31363aSFangrui Song   ReachesFunctionCallback(label, 0, file, line, function);
7645bb06c7cSAndrew Browne }
7655bb06c7cSAndrew Browne 
7665bb06c7cSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
7675bb06c7cSAndrew Browne dfsan_set_reaches_function_callback(
7685bb06c7cSAndrew Browne     __dfsan::dfsan_reaches_function_callback_t callback) {
769fe31363aSFangrui Song   reaches_function_callback = callback;
7705bb06c7cSAndrew Browne }
7715bb06c7cSAndrew Browne 
7725bb06c7cSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
7735bb06c7cSAndrew Browne dfsan_get_labels_in_signal_reaches_function() {
774fe31363aSFangrui Song   return labels_in_signal_reaches_function;
7755bb06c7cSAndrew Browne }
7765bb06c7cSAndrew Browne 
77780eea015SFangrui Song namespace {
778c20db7eaSJianzhou Zhao class Decorator : public __sanitizer::SanitizerCommonDecorator {
779c20db7eaSJianzhou Zhao  public:
780c20db7eaSJianzhou Zhao   Decorator() : SanitizerCommonDecorator() {}
781c20db7eaSJianzhou Zhao   const char *Origin() const { return Magenta(); }
782c20db7eaSJianzhou Zhao };
78380eea015SFangrui Song }  // namespace
784c20db7eaSJianzhou Zhao 
78580eea015SFangrui Song static void PrintNoOriginTrackingWarning() {
786a11cb10aSGeorge Balatsouras   Decorator d;
787c20db7eaSJianzhou Zhao   Printf(
788c20db7eaSJianzhou Zhao       "  %sDFSan: origin tracking is not enabled. Did you specify the "
789c20db7eaSJianzhou Zhao       "-dfsan-track-origins=1 option?%s\n",
790c20db7eaSJianzhou Zhao       d.Warning(), d.Default());
791c20db7eaSJianzhou Zhao }
792c20db7eaSJianzhou Zhao 
79380eea015SFangrui Song static void PrintNoTaintWarning(const void *address) {
794a11cb10aSGeorge Balatsouras   Decorator d;
795a11cb10aSGeorge Balatsouras   Printf("  %sDFSan: no tainted value at %x%s\n", d.Warning(), address,
796c20db7eaSJianzhou Zhao          d.Default());
797c20db7eaSJianzhou Zhao }
798c20db7eaSJianzhou Zhao 
79980eea015SFangrui Song static void PrintInvalidOriginWarning(dfsan_label label, const void *address) {
800a11cb10aSGeorge Balatsouras   Decorator d;
801a11cb10aSGeorge Balatsouras   Printf(
802a11cb10aSGeorge Balatsouras       "  %sTaint value 0x%x (at %p) has invalid origin tracking. This can "
803a11cb10aSGeorge Balatsouras       "be a DFSan bug.%s\n",
804a11cb10aSGeorge Balatsouras       d.Warning(), label, address, d.Default());
805a11cb10aSGeorge Balatsouras }
806a11cb10aSGeorge Balatsouras 
80780eea015SFangrui Song static void PrintInvalidOriginIdWarning(dfsan_origin origin) {
808a11cb10aSGeorge Balatsouras   Decorator d;
809ed6c757dSAndrew Browne   Printf(
810ed6c757dSAndrew Browne       "  %sOrigin Id %d has invalid origin tracking. This can "
811ed6c757dSAndrew Browne       "be a DFSan bug.%s\n",
812ed6c757dSAndrew Browne       d.Warning(), origin, d.Default());
813ed6c757dSAndrew Browne }
814a11cb10aSGeorge Balatsouras 
81580eea015SFangrui Song static bool PrintOriginTraceFramesToStr(Origin o, InternalScopedString *out) {
816ed6c757dSAndrew Browne   Decorator d;
817c20db7eaSJianzhou Zhao   bool found = false;
818a11cb10aSGeorge Balatsouras 
819c20db7eaSJianzhou Zhao   while (o.isChainedOrigin()) {
820c20db7eaSJianzhou Zhao     StackTrace stack;
821c20db7eaSJianzhou Zhao     dfsan_origin origin_id = o.raw_id();
822c20db7eaSJianzhou Zhao     o = o.getNextChainedOrigin(&stack);
823c20db7eaSJianzhou Zhao     if (o.isChainedOrigin())
8245b7dfa96SVitaly Buka       out->AppendF(
825a11cb10aSGeorge Balatsouras           "  %sOrigin value: 0x%x, Taint value was stored to memory at%s\n",
826c20db7eaSJianzhou Zhao           d.Origin(), origin_id, d.Default());
827c20db7eaSJianzhou Zhao     else
8285b7dfa96SVitaly Buka       out->AppendF("  %sOrigin value: 0x%x, Taint value was created at%s\n",
829c20db7eaSJianzhou Zhao                    d.Origin(), origin_id, d.Default());
830a11cb10aSGeorge Balatsouras 
831a11cb10aSGeorge Balatsouras     // Includes a trailing newline, so no need to add it again.
832a11cb10aSGeorge Balatsouras     stack.PrintTo(out);
833c20db7eaSJianzhou Zhao     found = true;
834c20db7eaSJianzhou Zhao   }
835a11cb10aSGeorge Balatsouras 
836a11cb10aSGeorge Balatsouras   return found;
837a11cb10aSGeorge Balatsouras }
838a11cb10aSGeorge Balatsouras 
83980eea015SFangrui Song static bool PrintOriginTraceToStr(const void *addr, const char *description,
840ed6c757dSAndrew Browne                                   InternalScopedString *out) {
841ed6c757dSAndrew Browne   CHECK(out);
842ed6c757dSAndrew Browne   CHECK(dfsan_get_track_origins());
843ed6c757dSAndrew Browne   Decorator d;
844ed6c757dSAndrew Browne 
845ed6c757dSAndrew Browne   const dfsan_label label = *__dfsan::shadow_for(addr);
846ed6c757dSAndrew Browne   CHECK(label);
847ed6c757dSAndrew Browne 
848ed6c757dSAndrew Browne   const dfsan_origin origin = *__dfsan::origin_for(addr);
849ed6c757dSAndrew Browne 
8505b7dfa96SVitaly Buka   out->AppendF("  %sTaint value 0x%x (at %p) origin tracking (%s)%s\n",
851ed6c757dSAndrew Browne                d.Origin(), label, addr, description ? description : "",
852ed6c757dSAndrew Browne                d.Default());
853ed6c757dSAndrew Browne 
854ed6c757dSAndrew Browne   Origin o = Origin::FromRawId(origin);
855ed6c757dSAndrew Browne   return PrintOriginTraceFramesToStr(o, out);
856ed6c757dSAndrew Browne }
857ed6c757dSAndrew Browne 
858a11cb10aSGeorge Balatsouras extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace(
859a11cb10aSGeorge Balatsouras     const void *addr, const char *description) {
860ae6648ceSJianzhou Zhao   if (!dfsan_get_track_origins()) {
861a11cb10aSGeorge Balatsouras     PrintNoOriginTrackingWarning();
862a11cb10aSGeorge Balatsouras     return;
863a11cb10aSGeorge Balatsouras   }
864a11cb10aSGeorge Balatsouras 
865a11cb10aSGeorge Balatsouras   const dfsan_label label = *__dfsan::shadow_for(addr);
866a11cb10aSGeorge Balatsouras   if (!label) {
867a11cb10aSGeorge Balatsouras     PrintNoTaintWarning(addr);
868a11cb10aSGeorge Balatsouras     return;
869a11cb10aSGeorge Balatsouras   }
870a11cb10aSGeorge Balatsouras 
871a11cb10aSGeorge Balatsouras   InternalScopedString trace;
872a11cb10aSGeorge Balatsouras   bool success = PrintOriginTraceToStr(addr, description, &trace);
873a11cb10aSGeorge Balatsouras 
874a11cb10aSGeorge Balatsouras   if (trace.length())
875a11cb10aSGeorge Balatsouras     Printf("%s", trace.data());
876a11cb10aSGeorge Balatsouras 
877a11cb10aSGeorge Balatsouras   if (!success)
878a11cb10aSGeorge Balatsouras     PrintInvalidOriginWarning(label, addr);
879a11cb10aSGeorge Balatsouras }
880a11cb10aSGeorge Balatsouras 
881df43d419SVitaly Buka extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
882a11cb10aSGeorge Balatsouras dfsan_sprint_origin_trace(const void *addr, const char *description,
883df43d419SVitaly Buka                           char *out_buf, uptr out_buf_size) {
884a11cb10aSGeorge Balatsouras   CHECK(out_buf);
885a11cb10aSGeorge Balatsouras 
886ae6648ceSJianzhou Zhao   if (!dfsan_get_track_origins()) {
887a11cb10aSGeorge Balatsouras     PrintNoOriginTrackingWarning();
888a11cb10aSGeorge Balatsouras     return 0;
889a11cb10aSGeorge Balatsouras   }
890a11cb10aSGeorge Balatsouras 
891a11cb10aSGeorge Balatsouras   const dfsan_label label = *__dfsan::shadow_for(addr);
892a11cb10aSGeorge Balatsouras   if (!label) {
893a11cb10aSGeorge Balatsouras     PrintNoTaintWarning(addr);
894a11cb10aSGeorge Balatsouras     return 0;
895a11cb10aSGeorge Balatsouras   }
896a11cb10aSGeorge Balatsouras 
897a11cb10aSGeorge Balatsouras   InternalScopedString trace;
898a11cb10aSGeorge Balatsouras   bool success = PrintOriginTraceToStr(addr, description, &trace);
899a11cb10aSGeorge Balatsouras 
900a11cb10aSGeorge Balatsouras   if (!success) {
901a11cb10aSGeorge Balatsouras     PrintInvalidOriginWarning(label, addr);
902a11cb10aSGeorge Balatsouras     return 0;
903a11cb10aSGeorge Balatsouras   }
904a11cb10aSGeorge Balatsouras 
905a11cb10aSGeorge Balatsouras   if (out_buf_size) {
906a11cb10aSGeorge Balatsouras     internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
907a11cb10aSGeorge Balatsouras     out_buf[out_buf_size - 1] = '\0';
908a11cb10aSGeorge Balatsouras   }
909a11cb10aSGeorge Balatsouras 
910a11cb10aSGeorge Balatsouras   return trace.length();
911c20db7eaSJianzhou Zhao }
912c20db7eaSJianzhou Zhao 
913ed6c757dSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_id_trace(
914ed6c757dSAndrew Browne     dfsan_origin origin) {
915ed6c757dSAndrew Browne   if (!dfsan_get_track_origins()) {
916ed6c757dSAndrew Browne     PrintNoOriginTrackingWarning();
917ed6c757dSAndrew Browne     return;
918ed6c757dSAndrew Browne   }
919ed6c757dSAndrew Browne   Origin o = Origin::FromRawId(origin);
920ed6c757dSAndrew Browne 
921ed6c757dSAndrew Browne   InternalScopedString trace;
922ed6c757dSAndrew Browne   bool success = PrintOriginTraceFramesToStr(o, &trace);
923ed6c757dSAndrew Browne 
924ed6c757dSAndrew Browne   if (trace.length())
925ed6c757dSAndrew Browne     Printf("%s", trace.data());
926ed6c757dSAndrew Browne 
927ed6c757dSAndrew Browne   if (!success)
928ed6c757dSAndrew Browne     PrintInvalidOriginIdWarning(origin);
929ed6c757dSAndrew Browne }
930ed6c757dSAndrew Browne 
931ed6c757dSAndrew Browne extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_sprint_origin_id_trace(
932ed6c757dSAndrew Browne     dfsan_origin origin, char *out_buf, uptr out_buf_size) {
933ed6c757dSAndrew Browne   CHECK(out_buf);
934ed6c757dSAndrew Browne 
935ed6c757dSAndrew Browne   if (!dfsan_get_track_origins()) {
936ed6c757dSAndrew Browne     PrintNoOriginTrackingWarning();
937ed6c757dSAndrew Browne     return 0;
938ed6c757dSAndrew Browne   }
939ed6c757dSAndrew Browne   Origin o = Origin::FromRawId(origin);
940ed6c757dSAndrew Browne 
941ed6c757dSAndrew Browne   InternalScopedString trace;
942ed6c757dSAndrew Browne   bool success = PrintOriginTraceFramesToStr(o, &trace);
943ed6c757dSAndrew Browne 
944ed6c757dSAndrew Browne   if (!success) {
945ed6c757dSAndrew Browne     PrintInvalidOriginIdWarning(origin);
946ed6c757dSAndrew Browne     return 0;
947ed6c757dSAndrew Browne   }
948ed6c757dSAndrew Browne 
949ed6c757dSAndrew Browne   if (out_buf_size) {
950ed6c757dSAndrew Browne     internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
951ed6c757dSAndrew Browne     out_buf[out_buf_size - 1] = '\0';
952ed6c757dSAndrew Browne   }
953ed6c757dSAndrew Browne 
954ed6c757dSAndrew Browne   return trace.length();
955ed6c757dSAndrew Browne }
956ed6c757dSAndrew Browne 
957c20db7eaSJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
958c20db7eaSJianzhou Zhao dfsan_get_init_origin(const void *addr) {
959ae6648ceSJianzhou Zhao   if (!dfsan_get_track_origins())
960c20db7eaSJianzhou Zhao     return 0;
961c20db7eaSJianzhou Zhao 
962c20db7eaSJianzhou Zhao   const dfsan_label label = *__dfsan::shadow_for(addr);
963c20db7eaSJianzhou Zhao   if (!label)
964c20db7eaSJianzhou Zhao     return 0;
965c20db7eaSJianzhou Zhao 
966c20db7eaSJianzhou Zhao   const dfsan_origin origin = *__dfsan::origin_for(addr);
967c20db7eaSJianzhou Zhao 
968c20db7eaSJianzhou Zhao   Origin o = Origin::FromRawId(origin);
969c20db7eaSJianzhou Zhao   dfsan_origin origin_id = o.raw_id();
970c20db7eaSJianzhou Zhao   while (o.isChainedOrigin()) {
971c20db7eaSJianzhou Zhao     StackTrace stack;
9724e67ae7bSJianzhou Zhao     origin_id = o.raw_id();
973c20db7eaSJianzhou Zhao     o = o.getNextChainedOrigin(&stack);
974c20db7eaSJianzhou Zhao   }
975c20db7eaSJianzhou Zhao   return origin_id;
976c20db7eaSJianzhou Zhao }
977c20db7eaSJianzhou Zhao 
9783597fba4SJianzhou Zhao void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
9793597fba4SJianzhou Zhao                                                  void *context,
9803597fba4SJianzhou Zhao                                                  bool request_fast,
9813597fba4SJianzhou Zhao                                                  u32 max_depth) {
9820f3fd3b2SJianzhou Zhao   using namespace __dfsan;
9830f3fd3b2SJianzhou Zhao   DFsanThread *t = GetCurrentThread();
9840f3fd3b2SJianzhou Zhao   if (!t || !StackTrace::WillUseFastUnwind(request_fast)) {
9850f3fd3b2SJianzhou Zhao     return Unwind(max_depth, pc, bp, context, 0, 0, false);
9860f3fd3b2SJianzhou Zhao   }
9870f3fd3b2SJianzhou Zhao   Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true);
9883597fba4SJianzhou Zhao }
9893597fba4SJianzhou Zhao 
9903597fba4SJianzhou Zhao extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() {
99198504959SGeorge Balatsouras   GET_CALLER_PC_BP;
99298504959SGeorge Balatsouras   GET_STORE_STACK_TRACE_PC_BP(pc, bp);
9933597fba4SJianzhou Zhao   stack.Print();
9943597fba4SJianzhou Zhao }
9953597fba4SJianzhou Zhao 
996df43d419SVitaly Buka extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
997df43d419SVitaly Buka dfsan_sprint_stack_trace(char *out_buf, uptr out_buf_size) {
99898504959SGeorge Balatsouras   CHECK(out_buf);
99998504959SGeorge Balatsouras   GET_CALLER_PC_BP;
100098504959SGeorge Balatsouras   GET_STORE_STACK_TRACE_PC_BP(pc, bp);
100198504959SGeorge Balatsouras   return stack.PrintTo(out_buf, out_buf_size);
100298504959SGeorge Balatsouras }
100398504959SGeorge Balatsouras 
1004a9aa8137SNico Weber void Flags::SetDefaults() {
1005a9aa8137SNico Weber #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
1006a9aa8137SNico Weber #include "dfsan_flags.inc"
1007a9aa8137SNico Weber #undef DFSAN_FLAG
1008a9aa8137SNico Weber }
1009a9aa8137SNico Weber 
1010a9aa8137SNico Weber static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
1011a9aa8137SNico Weber #define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
1012a9aa8137SNico Weber   RegisterFlag(parser, #Name, Description, &f->Name);
1013a9aa8137SNico Weber #include "dfsan_flags.inc"
1014a9aa8137SNico Weber #undef DFSAN_FLAG
1015a9aa8137SNico Weber }
1016a9aa8137SNico Weber 
1017a9aa8137SNico Weber static void InitializeFlags() {
1018a9aa8137SNico Weber   SetCommonFlagsDefaults();
10191fb612d0SJianzhou Zhao   {
10201fb612d0SJianzhou Zhao     CommonFlags cf;
10211fb612d0SJianzhou Zhao     cf.CopyFrom(*common_flags());
10221fb612d0SJianzhou Zhao     cf.intercept_tls_get_addr = true;
10231fb612d0SJianzhou Zhao     OverrideCommonFlags(cf);
10241fb612d0SJianzhou Zhao   }
1025a9aa8137SNico Weber   flags().SetDefaults();
1026a9aa8137SNico Weber 
1027a9aa8137SNico Weber   FlagParser parser;
1028a9aa8137SNico Weber   RegisterCommonFlags(&parser);
1029a9aa8137SNico Weber   RegisterDfsanFlags(&parser, &flags());
1030a9aa8137SNico Weber   parser.ParseStringFromEnv("DFSAN_OPTIONS");
1031a9aa8137SNico Weber   InitializeCommonFlags();
1032a9aa8137SNico Weber   if (Verbosity()) ReportUnrecognizedFlags();
1033a9aa8137SNico Weber   if (common_flags()->help) parser.PrintFlagDescriptions();
1034a9aa8137SNico Weber }
1035a9aa8137SNico Weber 
1036e1a4322fSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1037e1a4322fSJianzhou Zhao void dfsan_clear_arg_tls(uptr offset, uptr size) {
1038e1a4322fSJianzhou Zhao   internal_memset((void *)((uptr)__dfsan_arg_tls + offset), 0, size);
1039e1a4322fSJianzhou Zhao }
1040e1a4322fSJianzhou Zhao 
1041e1a4322fSJianzhou Zhao SANITIZER_INTERFACE_ATTRIBUTE
1042e1a4322fSJianzhou Zhao void dfsan_clear_thread_local_state() {
1043e1a4322fSJianzhou Zhao   internal_memset(__dfsan_arg_tls, 0, sizeof(__dfsan_arg_tls));
1044e1a4322fSJianzhou Zhao   internal_memset(__dfsan_retval_tls, 0, sizeof(__dfsan_retval_tls));
1045063a6fa8SJianzhou Zhao 
1046ae6648ceSJianzhou Zhao   if (dfsan_get_track_origins()) {
1047063a6fa8SJianzhou Zhao     internal_memset(__dfsan_arg_origin_tls, 0, sizeof(__dfsan_arg_origin_tls));
1048063a6fa8SJianzhou Zhao     internal_memset(&__dfsan_retval_origin_tls, 0,
1049063a6fa8SJianzhou Zhao                     sizeof(__dfsan_retval_origin_tls));
1050063a6fa8SJianzhou Zhao   }
1051e1a4322fSJianzhou Zhao }
1052e1a4322fSJianzhou Zhao 
1053dbf8c00bSAndrew Browne SANITIZER_INTERFACE_ATTRIBUTE
1054dbf8c00bSAndrew Browne void dfsan_set_arg_tls(uptr offset, dfsan_label label) {
1055dbf8c00bSAndrew Browne   // 2x to match ShadowTLSAlignment.
1056dbf8c00bSAndrew Browne   // ShadowTLSAlignment should probably be changed.
1057dbf8c00bSAndrew Browne   // TODO: Consider reducing ShadowTLSAlignment to 1.
1058dbf8c00bSAndrew Browne   // Aligning to 2 bytes is probably a remnant of fast16 mode.
1059dbf8c00bSAndrew Browne   ((dfsan_label *)__dfsan_arg_tls)[offset * 2] = label;
1060dbf8c00bSAndrew Browne }
1061dbf8c00bSAndrew Browne 
1062dbf8c00bSAndrew Browne SANITIZER_INTERFACE_ATTRIBUTE
1063dbf8c00bSAndrew Browne void dfsan_set_arg_origin_tls(uptr offset, dfsan_origin o) {
1064dbf8c00bSAndrew Browne   __dfsan_arg_origin_tls[offset] = o;
1065dbf8c00bSAndrew Browne }
1066dbf8c00bSAndrew Browne 
1067a9aa8137SNico Weber extern "C" void dfsan_flush() {
106845f6d552SAndrew Browne   const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
106945f6d552SAndrew Browne   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
107045f6d552SAndrew Browne     uptr start = kMemoryLayout[i].start;
107145f6d552SAndrew Browne     uptr end = kMemoryLayout[i].end;
107245f6d552SAndrew Browne     uptr size = end - start;
107345f6d552SAndrew Browne     MappingDesc::Type type = kMemoryLayout[i].type;
107445f6d552SAndrew Browne 
107545f6d552SAndrew Browne     if (type != MappingDesc::SHADOW && type != MappingDesc::ORIGIN)
107645f6d552SAndrew Browne       continue;
107745f6d552SAndrew Browne 
107845f6d552SAndrew Browne     // Check if the segment should be mapped based on platform constraints.
107945f6d552SAndrew Browne     if (start >= maxVirtualAddress)
108045f6d552SAndrew Browne       continue;
108145f6d552SAndrew Browne 
108245f6d552SAndrew Browne     if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) {
108345f6d552SAndrew Browne       Printf("FATAL: DataFlowSanitizer: failed to clear memory region\n");
1084a9aa8137SNico Weber       Die();
1085a9aa8137SNico Weber     }
108645f6d552SAndrew Browne   }
1087fe31363aSFangrui Song   labels_in_signal_conditional = 0;
1088fe31363aSFangrui Song   labels_in_signal_reaches_function = 0;
108945f6d552SAndrew Browne }
109045f6d552SAndrew Browne 
109145f6d552SAndrew Browne // TODO: CheckMemoryLayoutSanity is based on msan.
109245f6d552SAndrew Browne // Consider refactoring these into a shared implementation.
109345f6d552SAndrew Browne static void CheckMemoryLayoutSanity() {
109445f6d552SAndrew Browne   uptr prev_end = 0;
109545f6d552SAndrew Browne   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
109645f6d552SAndrew Browne     uptr start = kMemoryLayout[i].start;
109745f6d552SAndrew Browne     uptr end = kMemoryLayout[i].end;
109845f6d552SAndrew Browne     MappingDesc::Type type = kMemoryLayout[i].type;
109945f6d552SAndrew Browne     CHECK_LT(start, end);
110045f6d552SAndrew Browne     CHECK_EQ(prev_end, start);
110145f6d552SAndrew Browne     CHECK(addr_is_type(start, type));
110245f6d552SAndrew Browne     CHECK(addr_is_type((start + end) / 2, type));
110345f6d552SAndrew Browne     CHECK(addr_is_type(end - 1, type));
110445f6d552SAndrew Browne     if (type == MappingDesc::APP) {
110545f6d552SAndrew Browne       uptr addr = start;
110645f6d552SAndrew Browne       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
110745f6d552SAndrew Browne       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
110845f6d552SAndrew Browne       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
110945f6d552SAndrew Browne 
111045f6d552SAndrew Browne       addr = (start + end) / 2;
111145f6d552SAndrew Browne       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
111245f6d552SAndrew Browne       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
111345f6d552SAndrew Browne       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
111445f6d552SAndrew Browne 
111545f6d552SAndrew Browne       addr = end - 1;
111645f6d552SAndrew Browne       CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
111745f6d552SAndrew Browne       CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
111845f6d552SAndrew Browne       CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
111945f6d552SAndrew Browne     }
112045f6d552SAndrew Browne     prev_end = end;
112145f6d552SAndrew Browne   }
112245f6d552SAndrew Browne }
112345f6d552SAndrew Browne 
112445f6d552SAndrew Browne // TODO: CheckMemoryRangeAvailability is based on msan.
112545f6d552SAndrew Browne // Consider refactoring these into a shared implementation.
112662ed009cSThurston Dang static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {
112745f6d552SAndrew Browne   if (size > 0) {
112845f6d552SAndrew Browne     uptr end = beg + size - 1;
112945f6d552SAndrew Browne     if (!MemoryRangeIsAvailable(beg, end)) {
113062ed009cSThurston Dang       if (verbose)
113145f6d552SAndrew Browne         Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
113245f6d552SAndrew Browne       return false;
113345f6d552SAndrew Browne     }
113445f6d552SAndrew Browne   }
113545f6d552SAndrew Browne   return true;
113645f6d552SAndrew Browne }
113745f6d552SAndrew Browne 
113845f6d552SAndrew Browne // TODO: ProtectMemoryRange is based on msan.
113945f6d552SAndrew Browne // Consider refactoring these into a shared implementation.
114045f6d552SAndrew Browne static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
114145f6d552SAndrew Browne   if (size > 0) {
114245f6d552SAndrew Browne     void *addr = MmapFixedNoAccess(beg, size, name);
114345f6d552SAndrew Browne     if (beg == 0 && addr) {
114445f6d552SAndrew Browne       // Depending on the kernel configuration, we may not be able to protect
114545f6d552SAndrew Browne       // the page at address zero.
114645f6d552SAndrew Browne       uptr gap = 16 * GetPageSizeCached();
114745f6d552SAndrew Browne       beg += gap;
114845f6d552SAndrew Browne       size -= gap;
114945f6d552SAndrew Browne       addr = MmapFixedNoAccess(beg, size, name);
115045f6d552SAndrew Browne     }
115145f6d552SAndrew Browne     if ((uptr)addr != beg) {
115245f6d552SAndrew Browne       uptr end = beg + size - 1;
115345f6d552SAndrew Browne       Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end,
115445f6d552SAndrew Browne              name);
115545f6d552SAndrew Browne       return false;
115645f6d552SAndrew Browne     }
115745f6d552SAndrew Browne   }
115845f6d552SAndrew Browne   return true;
115945f6d552SAndrew Browne }
116045f6d552SAndrew Browne 
116145f6d552SAndrew Browne // TODO: InitShadow is based on msan.
116245f6d552SAndrew Browne // Consider refactoring these into a shared implementation.
116380eea015SFangrui Song static bool InitShadow(bool init_origins, bool dry_run) {
116445f6d552SAndrew Browne   // Let user know mapping parameters first.
116513a442caSMartin Liska   VPrintf(1, "dfsan_init %p\n", (void *)&__dfsan::dfsan_init);
116645f6d552SAndrew Browne   for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
116745f6d552SAndrew Browne     VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
116845f6d552SAndrew Browne             kMemoryLayout[i].end - 1);
116945f6d552SAndrew Browne 
117045f6d552SAndrew Browne   CheckMemoryLayoutSanity();
117145f6d552SAndrew Browne 
117245f6d552SAndrew Browne   if (!MEM_IS_APP(&__dfsan::dfsan_init)) {
117362ed009cSThurston Dang     if (!dry_run)
117445f6d552SAndrew Browne       Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
117545f6d552SAndrew Browne              (uptr)&__dfsan::dfsan_init);
117645f6d552SAndrew Browne     return false;
117745f6d552SAndrew Browne   }
117845f6d552SAndrew Browne 
117945f6d552SAndrew Browne   const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
118045f6d552SAndrew Browne 
118145f6d552SAndrew Browne   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
118245f6d552SAndrew Browne     uptr start = kMemoryLayout[i].start;
118345f6d552SAndrew Browne     uptr end = kMemoryLayout[i].end;
118445f6d552SAndrew Browne     uptr size = end - start;
118545f6d552SAndrew Browne     MappingDesc::Type type = kMemoryLayout[i].type;
118645f6d552SAndrew Browne 
118745f6d552SAndrew Browne     // Check if the segment should be mapped based on platform constraints.
118845f6d552SAndrew Browne     if (start >= maxVirtualAddress)
118945f6d552SAndrew Browne       continue;
119045f6d552SAndrew Browne 
119145f6d552SAndrew Browne     bool map = type == MappingDesc::SHADOW ||
119245f6d552SAndrew Browne                (init_origins && type == MappingDesc::ORIGIN);
119345f6d552SAndrew Browne     bool protect = type == MappingDesc::INVALID ||
119445f6d552SAndrew Browne                    (!init_origins && type == MappingDesc::ORIGIN);
119545f6d552SAndrew Browne     CHECK(!(map && protect));
119662ed009cSThurston Dang     if (!map && !protect) {
119762ed009cSThurston Dang       CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);
119862ed009cSThurston Dang 
119962ed009cSThurston Dang       if (dry_run && type == MappingDesc::ALLOCATOR &&
120062ed009cSThurston Dang           !CheckMemoryRangeAvailability(start, size, !dry_run))
120162ed009cSThurston Dang         return false;
120262ed009cSThurston Dang     }
120345f6d552SAndrew Browne     if (map) {
120462ed009cSThurston Dang       if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
120545f6d552SAndrew Browne         return false;
120662ed009cSThurston Dang       if (!dry_run &&
120762ed009cSThurston Dang           !MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
120845f6d552SAndrew Browne         return false;
120962ed009cSThurston Dang       if (!dry_run && common_flags()->use_madv_dontdump)
121045f6d552SAndrew Browne         DontDumpShadowMemory(start, size);
121145f6d552SAndrew Browne     }
121245f6d552SAndrew Browne     if (protect) {
121362ed009cSThurston Dang       if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))
121445f6d552SAndrew Browne         return false;
121562ed009cSThurston Dang       if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))
121645f6d552SAndrew Browne         return false;
121745f6d552SAndrew Browne     }
121845f6d552SAndrew Browne   }
121945f6d552SAndrew Browne 
122045f6d552SAndrew Browne   return true;
122145f6d552SAndrew Browne }
1222a9aa8137SNico Weber 
122380eea015SFangrui Song static bool InitShadowWithReExec(bool init_origins) {
122462ed009cSThurston Dang   // Start with dry run: check layout is ok, but don't print warnings because
122562ed009cSThurston Dang   // warning messages will cause tests to fail (even if we successfully re-exec
122662ed009cSThurston Dang   // after the warning).
122762ed009cSThurston Dang   bool success = InitShadow(init_origins, true);
122862ed009cSThurston Dang   if (!success) {
122962ed009cSThurston Dang #if SANITIZER_LINUX
123062ed009cSThurston Dang     // Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.
123162ed009cSThurston Dang     int old_personality = personality(0xffffffff);
123262ed009cSThurston Dang     bool aslr_on =
123362ed009cSThurston Dang         (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
123462ed009cSThurston Dang 
123562ed009cSThurston Dang     if (aslr_on) {
123662ed009cSThurston Dang       VReport(1,
123762ed009cSThurston Dang               "WARNING: DataflowSanitizer: memory layout is incompatible, "
123862ed009cSThurston Dang               "possibly due to high-entropy ASLR.\n"
123962ed009cSThurston Dang               "Re-execing with fixed virtual address space.\n"
124062ed009cSThurston Dang               "N.B. reducing ASLR entropy is preferable.\n");
124162ed009cSThurston Dang       CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
124262ed009cSThurston Dang       ReExec();
124362ed009cSThurston Dang     }
124462ed009cSThurston Dang #endif
124562ed009cSThurston Dang   }
124662ed009cSThurston Dang 
124762ed009cSThurston Dang   // The earlier dry run didn't actually map or protect anything. Run again in
124862ed009cSThurston Dang   // non-dry run mode.
124962ed009cSThurston Dang   return success && InitShadow(init_origins, false);
125062ed009cSThurston Dang }
125162ed009cSThurston Dang 
12521fb612d0SJianzhou Zhao static void DFsanInit(int argc, char **argv, char **envp) {
12531fb612d0SJianzhou Zhao   CHECK(!dfsan_init_is_running);
12541fb612d0SJianzhou Zhao   if (dfsan_inited)
12551fb612d0SJianzhou Zhao     return;
12561fb612d0SJianzhou Zhao   dfsan_init_is_running = true;
12571fb612d0SJianzhou Zhao   SanitizerToolName = "DataflowSanitizer";
12581fb612d0SJianzhou Zhao 
125914407332SAndrew Browne   AvoidCVE_2016_2143();
1260a9aa8137SNico Weber 
126114407332SAndrew Browne   InitializeFlags();
126239295e92SAndrew Browne 
126345f6d552SAndrew Browne   CheckASLR();
1264a9aa8137SNico Weber 
1265*a0bb2e21SVitaly Buka   InitializePlatformEarly();
1266*a0bb2e21SVitaly Buka 
126762ed009cSThurston Dang   if (!InitShadowWithReExec(dfsan_get_track_origins())) {
126862ed009cSThurston Dang     Printf("FATAL: DataflowSanitizer can not mmap the shadow memory.\n");
126962ed009cSThurston Dang     DumpProcessMap();
127062ed009cSThurston Dang     Die();
127162ed009cSThurston Dang   }
1272a9aa8137SNico Weber 
12732c82588dSJianzhou Zhao   initialize_interceptors();
1274a9aa8137SNico Weber 
12750f3fd3b2SJianzhou Zhao   // Set up threads
12760f3fd3b2SJianzhou Zhao   DFsanTSDInit(DFsanTSDDtor);
12771fb612d0SJianzhou Zhao 
12781fb612d0SJianzhou Zhao   dfsan_allocator_init();
12791fb612d0SJianzhou Zhao 
1280dbf8c00bSAndrew Browne   DFsanThread *main_thread = DFsanThread::Create(nullptr, nullptr);
12810f3fd3b2SJianzhou Zhao   SetCurrentThread(main_thread);
128263886c21SVitaly Buka   main_thread->Init();
12830f3fd3b2SJianzhou Zhao 
12841fb612d0SJianzhou Zhao   dfsan_init_is_running = false;
12851fb612d0SJianzhou Zhao   dfsan_inited = true;
1286a9aa8137SNico Weber }
1287a9aa8137SNico Weber 
128880eea015SFangrui Song void __dfsan::dfsan_init() { DFsanInit(0, nullptr, nullptr); }
12891fb612d0SJianzhou Zhao 
1290a9aa8137SNico Weber #if SANITIZER_CAN_USE_PREINIT_ARRAY
12911fb612d0SJianzhou Zhao __attribute__((section(".preinit_array"),
12921fb612d0SJianzhou Zhao                used)) static void (*dfsan_init_ptr)(int, char **,
12931fb612d0SJianzhou Zhao                                                     char **) = DFsanInit;
1294a9aa8137SNico Weber #endif
1295