13cab2bb3Spatrick //===-- dfsan.cpp ---------------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of DataFlowSanitizer.
103cab2bb3Spatrick //
113cab2bb3Spatrick // DataFlowSanitizer runtime. This file defines the public interface to
123cab2bb3Spatrick // DataFlowSanitizer as well as the definition of certain runtime functions
133cab2bb3Spatrick // called automatically by the compiler (specifically the instrumentation pass
143cab2bb3Spatrick // in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).
153cab2bb3Spatrick //
163cab2bb3Spatrick // The public interface is defined in include/sanitizer/dfsan_interface.h whose
173cab2bb3Spatrick // functions are prefixed dfsan_ while the compiler interface functions are
183cab2bb3Spatrick // prefixed __dfsan_.
193cab2bb3Spatrick //===----------------------------------------------------------------------===//
203cab2bb3Spatrick
21d89ec533Spatrick #include "dfsan/dfsan.h"
22d89ec533Spatrick
23d89ec533Spatrick #include "dfsan/dfsan_chained_origin_depot.h"
24d89ec533Spatrick #include "dfsan/dfsan_flags.h"
25d89ec533Spatrick #include "dfsan/dfsan_origin.h"
26d89ec533Spatrick #include "dfsan/dfsan_thread.h"
273cab2bb3Spatrick #include "sanitizer_common/sanitizer_atomic.h"
283cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
293cab2bb3Spatrick #include "sanitizer_common/sanitizer_file.h"
303cab2bb3Spatrick #include "sanitizer_common/sanitizer_flag_parser.h"
31d89ec533Spatrick #include "sanitizer_common/sanitizer_flags.h"
32d89ec533Spatrick #include "sanitizer_common/sanitizer_internal_defs.h"
333cab2bb3Spatrick #include "sanitizer_common/sanitizer_libc.h"
34d89ec533Spatrick #include "sanitizer_common/sanitizer_report_decorator.h"
35d89ec533Spatrick #include "sanitizer_common/sanitizer_stacktrace.h"
363cab2bb3Spatrick
373cab2bb3Spatrick using namespace __dfsan;
383cab2bb3Spatrick
393cab2bb3Spatrick Flags __dfsan::flags_data;
403cab2bb3Spatrick
41d89ec533Spatrick // The size of TLS variables. These constants must be kept in sync with the ones
42d89ec533Spatrick // in DataFlowSanitizer.cpp.
43d89ec533Spatrick static const int kDFsanArgTlsSize = 800;
44d89ec533Spatrick static const int kDFsanRetvalTlsSize = 800;
45d89ec533Spatrick static const int kDFsanArgOriginTlsSize = 800;
463cab2bb3Spatrick
47d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64
48d89ec533Spatrick __dfsan_retval_tls[kDFsanRetvalTlsSize / sizeof(u64)];
49d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __dfsan_retval_origin_tls;
50d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64
51d89ec533Spatrick __dfsan_arg_tls[kDFsanArgTlsSize / sizeof(u64)];
52d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32
53d89ec533Spatrick __dfsan_arg_origin_tls[kDFsanArgOriginTlsSize / sizeof(u32)];
54d89ec533Spatrick
55d89ec533Spatrick // Instrumented code may set this value in terms of -dfsan-track-origins.
56d89ec533Spatrick // * undefined or 0: do not track origins.
57d89ec533Spatrick // * 1: track origins at memory store operations.
58d89ec533Spatrick // * 2: track origins at memory load and store operations.
59d89ec533Spatrick // TODO: track callsites.
60d89ec533Spatrick extern "C" SANITIZER_WEAK_ATTRIBUTE const int __dfsan_track_origins;
61d89ec533Spatrick
dfsan_get_track_origins()62d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE int dfsan_get_track_origins() {
63d89ec533Spatrick return &__dfsan_track_origins ? __dfsan_track_origins : 0;
64d89ec533Spatrick }
653cab2bb3Spatrick
663cab2bb3Spatrick // On Linux/x86_64, memory is laid out as follows:
673cab2bb3Spatrick //
683cab2bb3Spatrick // +--------------------+ 0x800000000000 (top of memory)
69d89ec533Spatrick // | application 3 |
70d89ec533Spatrick // +--------------------+ 0x700000000000
71d89ec533Spatrick // | invalid |
72d89ec533Spatrick // +--------------------+ 0x610000000000
73d89ec533Spatrick // | origin 1 |
74d89ec533Spatrick // +--------------------+ 0x600000000000
75d89ec533Spatrick // | application 2 |
76d89ec533Spatrick // +--------------------+ 0x510000000000
77d89ec533Spatrick // | shadow 1 |
78d89ec533Spatrick // +--------------------+ 0x500000000000
79d89ec533Spatrick // | invalid |
80d89ec533Spatrick // +--------------------+ 0x400000000000
81d89ec533Spatrick // | origin 3 |
82d89ec533Spatrick // +--------------------+ 0x300000000000
83d89ec533Spatrick // | shadow 3 |
84d89ec533Spatrick // +--------------------+ 0x200000000000
85d89ec533Spatrick // | origin 2 |
86d89ec533Spatrick // +--------------------+ 0x110000000000
87d89ec533Spatrick // | invalid |
88d89ec533Spatrick // +--------------------+ 0x100000000000
89d89ec533Spatrick // | shadow 2 |
90d89ec533Spatrick // +--------------------+ 0x010000000000
91d89ec533Spatrick // | application 1 |
923cab2bb3Spatrick // +--------------------+ 0x000000000000
933cab2bb3Spatrick //
94d89ec533Spatrick // MEM_TO_SHADOW(mem) = mem ^ 0x500000000000
95d89ec533Spatrick // SHADOW_TO_ORIGIN(shadow) = shadow + 0x100000000000
963cab2bb3Spatrick
973cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE
__dfsan_union_load(const dfsan_label * ls,uptr n)983cab2bb3Spatrick dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {
993cab2bb3Spatrick dfsan_label label = ls[0];
100d89ec533Spatrick for (uptr i = 1; i != n; ++i)
101d89ec533Spatrick label |= ls[i];
1023cab2bb3Spatrick return label;
1033cab2bb3Spatrick }
1043cab2bb3Spatrick
105d89ec533Spatrick // Return the union of all the n labels from addr at the high 32 bit, and the
106d89ec533Spatrick // origin of the first taint byte at the low 32 bit.
107d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64
__dfsan_load_label_and_origin(const void * addr,uptr n)108d89ec533Spatrick __dfsan_load_label_and_origin(const void *addr, uptr n) {
109d89ec533Spatrick dfsan_label label = 0;
110d89ec533Spatrick u64 ret = 0;
111d89ec533Spatrick uptr p = (uptr)addr;
112d89ec533Spatrick dfsan_label *s = shadow_for((void *)p);
113d89ec533Spatrick for (uptr i = 0; i < n; ++i) {
114d89ec533Spatrick dfsan_label l = s[i];
115d89ec533Spatrick if (!l)
116d89ec533Spatrick continue;
117d89ec533Spatrick label |= l;
118d89ec533Spatrick if (!ret)
119d89ec533Spatrick ret = *(dfsan_origin *)origin_for((void *)(p + i));
120d89ec533Spatrick }
121d89ec533Spatrick return ret | (u64)label << 32;
122d89ec533Spatrick }
123d89ec533Spatrick
1243cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE
__dfsan_unimplemented(char * fname)1253cab2bb3Spatrick void __dfsan_unimplemented(char *fname) {
1263cab2bb3Spatrick if (flags().warn_unimplemented)
1273cab2bb3Spatrick Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",
1283cab2bb3Spatrick fname);
1293cab2bb3Spatrick }
1303cab2bb3Spatrick
__dfsan_wrapper_extern_weak_null(const void * addr,char * fname)131*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_wrapper_extern_weak_null(
132*810390e3Srobert const void *addr, char *fname) {
133*810390e3Srobert if (!addr)
134*810390e3Srobert Report(
135*810390e3Srobert "ERROR: DataFlowSanitizer: dfsan generated wrapper calling null "
136*810390e3Srobert "extern_weak function %s\nIf this only happens with dfsan, the "
137*810390e3Srobert "dfsan instrumentation pass may be accidentally optimizing out a "
138*810390e3Srobert "null check\n",
139*810390e3Srobert fname);
140*810390e3Srobert }
141*810390e3Srobert
1423cab2bb3Spatrick // Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function
1433cab2bb3Spatrick // to try to figure out where labels are being introduced in a nominally
1443cab2bb3Spatrick // label-free program.
__dfsan_nonzero_label()1453cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {
1463cab2bb3Spatrick if (flags().warn_nonzero_labels)
1473cab2bb3Spatrick Report("WARNING: DataFlowSanitizer: saw nonzero label\n");
1483cab2bb3Spatrick }
1493cab2bb3Spatrick
1503cab2bb3Spatrick // Indirect call to an uninstrumented vararg function. We don't have a way of
1513cab2bb3Spatrick // handling these at the moment.
1523cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__dfsan_vararg_wrapper(const char * fname)1533cab2bb3Spatrick __dfsan_vararg_wrapper(const char *fname) {
1543cab2bb3Spatrick Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "
1553cab2bb3Spatrick "function %s\n", fname);
1563cab2bb3Spatrick Die();
1573cab2bb3Spatrick }
1583cab2bb3Spatrick
159d89ec533Spatrick // Resolves the union of two labels.
1603cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
dfsan_union(dfsan_label l1,dfsan_label l2)1613cab2bb3Spatrick dfsan_union(dfsan_label l1, dfsan_label l2) {
162d89ec533Spatrick return l1 | l2;
1633cab2bb3Spatrick }
1643cab2bb3Spatrick
165d89ec533Spatrick static const uptr kOriginAlign = sizeof(dfsan_origin);
166d89ec533Spatrick static const uptr kOriginAlignMask = ~(kOriginAlign - 1UL);
167d89ec533Spatrick
OriginAlignUp(uptr u)168d89ec533Spatrick static uptr OriginAlignUp(uptr u) {
169d89ec533Spatrick return (u + kOriginAlign - 1) & kOriginAlignMask;
1703cab2bb3Spatrick }
1713cab2bb3Spatrick
OriginAlignDown(uptr u)172d89ec533Spatrick static uptr OriginAlignDown(uptr u) { return u & kOriginAlignMask; }
173d89ec533Spatrick
174d89ec533Spatrick // Return the origin of the first taint byte in the size bytes from the address
175d89ec533Spatrick // addr.
GetOriginIfTainted(uptr addr,uptr size)176d89ec533Spatrick static dfsan_origin GetOriginIfTainted(uptr addr, uptr size) {
177d89ec533Spatrick for (uptr i = 0; i < size; ++i, ++addr) {
178d89ec533Spatrick dfsan_label *s = shadow_for((void *)addr);
179d89ec533Spatrick
180d89ec533Spatrick if (*s) {
181d89ec533Spatrick // Validate address region.
182d89ec533Spatrick CHECK(MEM_IS_SHADOW(s));
183d89ec533Spatrick return *(dfsan_origin *)origin_for((void *)addr);
184d89ec533Spatrick }
185d89ec533Spatrick }
186d89ec533Spatrick return 0;
187d89ec533Spatrick }
188d89ec533Spatrick
189d89ec533Spatrick // For platforms which support slow unwinder only, we need to restrict the store
190d89ec533Spatrick // context size to 1, basically only storing the current pc, because the slow
191d89ec533Spatrick // unwinder which is based on libunwind is not async signal safe and causes
192d89ec533Spatrick // random freezes in forking applications as well as in signal handlers.
193d89ec533Spatrick // DFSan supports only Linux. So we do not restrict the store context size.
194d89ec533Spatrick #define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
195d89ec533Spatrick BufferedStackTrace stack; \
196d89ec533Spatrick stack.Unwind(pc, bp, nullptr, true, flags().store_context_size);
197d89ec533Spatrick
198d89ec533Spatrick #define PRINT_CALLER_STACK_TRACE \
199d89ec533Spatrick { \
200d89ec533Spatrick GET_CALLER_PC_BP_SP; \
201d89ec533Spatrick (void)sp; \
202d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp) \
203d89ec533Spatrick stack.Print(); \
204d89ec533Spatrick }
205d89ec533Spatrick
206d89ec533Spatrick // Return a chain with the previous ID id and the current stack.
207d89ec533Spatrick // from_init = true if this is the first chain of an origin tracking path.
ChainOrigin(u32 id,StackTrace * stack,bool from_init=false)208d89ec533Spatrick static u32 ChainOrigin(u32 id, StackTrace *stack, bool from_init = false) {
209d89ec533Spatrick // StackDepot is not async signal safe. Do not create new chains in a signal
210d89ec533Spatrick // handler.
211d89ec533Spatrick DFsanThread *t = GetCurrentThread();
212d89ec533Spatrick if (t && t->InSignalHandler())
213d89ec533Spatrick return id;
214d89ec533Spatrick
215d89ec533Spatrick // As an optimization the origin of an application byte is updated only when
216d89ec533Spatrick // its shadow is non-zero. Because we are only interested in the origins of
217d89ec533Spatrick // taint labels, it does not matter what origin a zero label has. This reduces
218d89ec533Spatrick // memory write cost. MSan does similar optimization. The following invariant
219d89ec533Spatrick // may not hold because of some bugs. We check the invariant to help debug.
220d89ec533Spatrick if (!from_init && id == 0 && flags().check_origin_invariant) {
221d89ec533Spatrick Printf(" DFSan found invalid origin invariant\n");
222d89ec533Spatrick PRINT_CALLER_STACK_TRACE
223d89ec533Spatrick }
224d89ec533Spatrick
225d89ec533Spatrick Origin o = Origin::FromRawId(id);
226d89ec533Spatrick stack->tag = StackTrace::TAG_UNKNOWN;
227d89ec533Spatrick Origin chained = Origin::CreateChainedOrigin(o, stack);
228d89ec533Spatrick return chained.raw_id();
229d89ec533Spatrick }
230d89ec533Spatrick
ChainAndWriteOriginIfTainted(uptr src,uptr size,uptr dst,StackTrace * stack)231d89ec533Spatrick static void ChainAndWriteOriginIfTainted(uptr src, uptr size, uptr dst,
232d89ec533Spatrick StackTrace *stack) {
233d89ec533Spatrick dfsan_origin o = GetOriginIfTainted(src, size);
234d89ec533Spatrick if (o) {
235d89ec533Spatrick o = ChainOrigin(o, stack);
236d89ec533Spatrick *(dfsan_origin *)origin_for((void *)dst) = o;
237d89ec533Spatrick }
238d89ec533Spatrick }
239d89ec533Spatrick
240d89ec533Spatrick // Copy the origins of the size bytes from src to dst. The source and target
241d89ec533Spatrick // memory ranges cannot be overlapped. This is used by memcpy. stack records the
242d89ec533Spatrick // stack trace of the memcpy. When dst and src are not 4-byte aligned properly,
243d89ec533Spatrick // origins at the unaligned address boundaries may be overwritten because four
244d89ec533Spatrick // contiguous bytes share the same origin.
CopyOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)245d89ec533Spatrick static void CopyOrigin(const void *dst, const void *src, uptr size,
246d89ec533Spatrick StackTrace *stack) {
247d89ec533Spatrick uptr d = (uptr)dst;
248d89ec533Spatrick uptr beg = OriginAlignDown(d);
249d89ec533Spatrick // Copy left unaligned origin if that memory is tainted.
250d89ec533Spatrick if (beg < d) {
251d89ec533Spatrick ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);
252d89ec533Spatrick beg += kOriginAlign;
253d89ec533Spatrick }
254d89ec533Spatrick
255d89ec533Spatrick uptr end = OriginAlignDown(d + size);
256d89ec533Spatrick // If both ends fall into the same 4-byte slot, we are done.
257d89ec533Spatrick if (end < beg)
258d89ec533Spatrick return;
259d89ec533Spatrick
260d89ec533Spatrick // Copy right unaligned origin if that memory is tainted.
261d89ec533Spatrick if (end < d + size)
262d89ec533Spatrick ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,
263d89ec533Spatrick stack);
264d89ec533Spatrick
265d89ec533Spatrick if (beg >= end)
266d89ec533Spatrick return;
267d89ec533Spatrick
268d89ec533Spatrick // Align src up.
269d89ec533Spatrick uptr src_a = OriginAlignUp((uptr)src);
270d89ec533Spatrick dfsan_origin *src_o = origin_for((void *)src_a);
271d89ec533Spatrick u32 *src_s = (u32 *)shadow_for((void *)src_a);
272d89ec533Spatrick dfsan_origin *src_end = origin_for((void *)(src_a + (end - beg)));
273d89ec533Spatrick dfsan_origin *dst_o = origin_for((void *)beg);
274d89ec533Spatrick dfsan_origin last_src_o = 0;
275d89ec533Spatrick dfsan_origin last_dst_o = 0;
276d89ec533Spatrick for (; src_o < src_end; ++src_o, ++src_s, ++dst_o) {
277d89ec533Spatrick if (!*src_s)
278d89ec533Spatrick continue;
279d89ec533Spatrick if (*src_o != last_src_o) {
280d89ec533Spatrick last_src_o = *src_o;
281d89ec533Spatrick last_dst_o = ChainOrigin(last_src_o, stack);
282d89ec533Spatrick }
283d89ec533Spatrick *dst_o = last_dst_o;
284d89ec533Spatrick }
285d89ec533Spatrick }
286d89ec533Spatrick
287d89ec533Spatrick // Copy the origins of the size bytes from src to dst. The source and target
288d89ec533Spatrick // memory ranges may be overlapped. So the copy is done in a reverse order.
289d89ec533Spatrick // This is used by memmove. stack records the stack trace of the memmove.
ReverseCopyOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)290d89ec533Spatrick static void ReverseCopyOrigin(const void *dst, const void *src, uptr size,
291d89ec533Spatrick StackTrace *stack) {
292d89ec533Spatrick uptr d = (uptr)dst;
293d89ec533Spatrick uptr end = OriginAlignDown(d + size);
294d89ec533Spatrick
295d89ec533Spatrick // Copy right unaligned origin if that memory is tainted.
296d89ec533Spatrick if (end < d + size)
297d89ec533Spatrick ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,
298d89ec533Spatrick stack);
299d89ec533Spatrick
300d89ec533Spatrick uptr beg = OriginAlignDown(d);
301d89ec533Spatrick
302d89ec533Spatrick if (beg + kOriginAlign < end) {
303d89ec533Spatrick // Align src up.
304d89ec533Spatrick uptr src_a = OriginAlignUp((uptr)src);
305d89ec533Spatrick void *src_end = (void *)(src_a + end - beg - kOriginAlign);
306d89ec533Spatrick dfsan_origin *src_end_o = origin_for(src_end);
307d89ec533Spatrick u32 *src_end_s = (u32 *)shadow_for(src_end);
308d89ec533Spatrick dfsan_origin *src_begin_o = origin_for((void *)src_a);
309d89ec533Spatrick dfsan_origin *dst = origin_for((void *)(end - kOriginAlign));
310d89ec533Spatrick dfsan_origin last_src_o = 0;
311d89ec533Spatrick dfsan_origin last_dst_o = 0;
312d89ec533Spatrick for (; src_end_o >= src_begin_o; --src_end_o, --src_end_s, --dst) {
313d89ec533Spatrick if (!*src_end_s)
314d89ec533Spatrick continue;
315d89ec533Spatrick if (*src_end_o != last_src_o) {
316d89ec533Spatrick last_src_o = *src_end_o;
317d89ec533Spatrick last_dst_o = ChainOrigin(last_src_o, stack);
318d89ec533Spatrick }
319d89ec533Spatrick *dst = last_dst_o;
320d89ec533Spatrick }
321d89ec533Spatrick }
322d89ec533Spatrick
323d89ec533Spatrick // Copy left unaligned origin if that memory is tainted.
324d89ec533Spatrick if (beg < d)
325d89ec533Spatrick ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);
326d89ec533Spatrick }
327d89ec533Spatrick
328d89ec533Spatrick // Copy or move the origins of the len bytes from src to dst. The source and
329d89ec533Spatrick // target memory ranges may or may not be overlapped. This is used by memory
330d89ec533Spatrick // transfer operations. stack records the stack trace of the memory transfer
331d89ec533Spatrick // operation.
MoveOrigin(const void * dst,const void * src,uptr size,StackTrace * stack)332d89ec533Spatrick static void MoveOrigin(const void *dst, const void *src, uptr size,
333d89ec533Spatrick StackTrace *stack) {
334d89ec533Spatrick // Validate address regions.
335d89ec533Spatrick if (!MEM_IS_SHADOW(shadow_for(dst)) ||
336d89ec533Spatrick !MEM_IS_SHADOW(shadow_for((void *)((uptr)dst + size))) ||
337d89ec533Spatrick !MEM_IS_SHADOW(shadow_for(src)) ||
338d89ec533Spatrick !MEM_IS_SHADOW(shadow_for((void *)((uptr)src + size)))) {
339d89ec533Spatrick CHECK(false);
340d89ec533Spatrick return;
341d89ec533Spatrick }
342d89ec533Spatrick // If destination origin range overlaps with source origin range, move
343d89ec533Spatrick // origins by copying origins in a reverse order; otherwise, copy origins in
344d89ec533Spatrick // a normal order. The orders of origin transfer are consistent with the
345d89ec533Spatrick // orders of how memcpy and memmove transfer user data.
346*810390e3Srobert uptr src_aligned_beg = OriginAlignDown((uptr)src);
347*810390e3Srobert uptr src_aligned_end = OriginAlignDown((uptr)src + size);
348*810390e3Srobert uptr dst_aligned_beg = OriginAlignDown((uptr)dst);
349d89ec533Spatrick if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)
350d89ec533Spatrick return ReverseCopyOrigin(dst, src, size, stack);
351d89ec533Spatrick return CopyOrigin(dst, src, size, stack);
352d89ec533Spatrick }
353d89ec533Spatrick
354d89ec533Spatrick // Set the size bytes from the addres dst to be the origin value.
SetOrigin(const void * dst,uptr size,u32 origin)355d89ec533Spatrick static void SetOrigin(const void *dst, uptr size, u32 origin) {
356d89ec533Spatrick if (size == 0)
357d89ec533Spatrick return;
358d89ec533Spatrick
359d89ec533Spatrick // Origin mapping is 4 bytes per 4 bytes of application memory.
360d89ec533Spatrick // Here we extend the range such that its left and right bounds are both
361d89ec533Spatrick // 4 byte aligned.
362d89ec533Spatrick uptr x = unaligned_origin_for((uptr)dst);
363d89ec533Spatrick uptr beg = OriginAlignDown(x);
364d89ec533Spatrick uptr end = OriginAlignUp(x + size); // align up.
365d89ec533Spatrick u64 origin64 = ((u64)origin << 32) | origin;
366d89ec533Spatrick // This is like memset, but the value is 32-bit. We unroll by 2 to write
367d89ec533Spatrick // 64 bits at once. May want to unroll further to get 128-bit stores.
368d89ec533Spatrick if (beg & 7ULL) {
369d89ec533Spatrick if (*(u32 *)beg != origin)
370d89ec533Spatrick *(u32 *)beg = origin;
371d89ec533Spatrick beg += 4;
372d89ec533Spatrick }
373d89ec533Spatrick for (uptr addr = beg; addr < (end & ~7UL); addr += 8) {
374d89ec533Spatrick if (*(u64 *)addr == origin64)
375d89ec533Spatrick continue;
376d89ec533Spatrick *(u64 *)addr = origin64;
377d89ec533Spatrick }
378d89ec533Spatrick if (end & 7ULL)
379d89ec533Spatrick if (*(u32 *)(end - kOriginAlign) != origin)
380d89ec533Spatrick *(u32 *)(end - kOriginAlign) = origin;
381d89ec533Spatrick }
382d89ec533Spatrick
383d89ec533Spatrick #define RET_CHAIN_ORIGIN(id) \
384d89ec533Spatrick GET_CALLER_PC_BP_SP; \
385d89ec533Spatrick (void)sp; \
386d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp); \
387d89ec533Spatrick return ChainOrigin(id, &stack);
388d89ec533Spatrick
389d89ec533Spatrick // Return a new origin chain with the previous ID id and the current stack
390d89ec533Spatrick // trace.
391d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
__dfsan_chain_origin(dfsan_origin id)392d89ec533Spatrick __dfsan_chain_origin(dfsan_origin id) {
393d89ec533Spatrick RET_CHAIN_ORIGIN(id)
394d89ec533Spatrick }
395d89ec533Spatrick
396d89ec533Spatrick // Return a new origin chain with the previous ID id and the current stack
397d89ec533Spatrick // trace if the label is tainted.
398d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
__dfsan_chain_origin_if_tainted(dfsan_label label,dfsan_origin id)399d89ec533Spatrick __dfsan_chain_origin_if_tainted(dfsan_label label, dfsan_origin id) {
400d89ec533Spatrick if (!label)
401d89ec533Spatrick return id;
402d89ec533Spatrick RET_CHAIN_ORIGIN(id)
403d89ec533Spatrick }
404d89ec533Spatrick
405d89ec533Spatrick // Copy or move the origins of the len bytes from src to dst.
__dfsan_mem_origin_transfer(const void * dst,const void * src,uptr len)406d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_mem_origin_transfer(
407d89ec533Spatrick const void *dst, const void *src, uptr len) {
408d89ec533Spatrick if (src == dst)
409d89ec533Spatrick return;
410d89ec533Spatrick GET_CALLER_PC_BP;
411d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp);
412d89ec533Spatrick MoveOrigin(dst, src, len, &stack);
413d89ec533Spatrick }
414d89ec533Spatrick
dfsan_mem_origin_transfer(const void * dst,const void * src,uptr len)415*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_origin_transfer(
416*810390e3Srobert const void *dst, const void *src, uptr len) {
417d89ec533Spatrick __dfsan_mem_origin_transfer(dst, src, len);
418d89ec533Spatrick }
419d89ec533Spatrick
CopyShadow(void * dst,const void * src,uptr len)420*810390e3Srobert static void CopyShadow(void *dst, const void *src, uptr len) {
421*810390e3Srobert internal_memcpy((void *)__dfsan::shadow_for(dst),
422*810390e3Srobert (const void *)__dfsan::shadow_for(src),
423*810390e3Srobert len * sizeof(dfsan_label));
424*810390e3Srobert }
425*810390e3Srobert
dfsan_mem_shadow_transfer(void * dst,const void * src,uptr len)426*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_shadow_transfer(
427*810390e3Srobert void *dst, const void *src, uptr len) {
428*810390e3Srobert CopyShadow(dst, src, len);
429*810390e3Srobert }
430*810390e3Srobert
431*810390e3Srobert // Copy shadow and origins of the len bytes from src to dst.
432*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__dfsan_mem_shadow_origin_transfer(void * dst,const void * src,uptr size)433*810390e3Srobert __dfsan_mem_shadow_origin_transfer(void *dst, const void *src, uptr size) {
434*810390e3Srobert if (src == dst)
435*810390e3Srobert return;
436*810390e3Srobert CopyShadow(dst, src, size);
437*810390e3Srobert if (dfsan_get_track_origins()) {
438*810390e3Srobert // Duplicating code instead of calling __dfsan_mem_origin_transfer
439*810390e3Srobert // so that the getting the caller stack frame works correctly.
440*810390e3Srobert GET_CALLER_PC_BP;
441*810390e3Srobert GET_STORE_STACK_TRACE_PC_BP(pc, bp);
442*810390e3Srobert MoveOrigin(dst, src, size, &stack);
443*810390e3Srobert }
444*810390e3Srobert }
445*810390e3Srobert
446*810390e3Srobert // Copy shadow and origins as per __atomic_compare_exchange.
447*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__dfsan_mem_shadow_origin_conditional_exchange(u8 condition,void * target,void * expected,const void * desired,uptr size)448*810390e3Srobert __dfsan_mem_shadow_origin_conditional_exchange(u8 condition, void *target,
449*810390e3Srobert void *expected,
450*810390e3Srobert const void *desired, uptr size) {
451*810390e3Srobert void *dst;
452*810390e3Srobert const void *src;
453*810390e3Srobert // condition is result of native call to __atomic_compare_exchange
454*810390e3Srobert if (condition) {
455*810390e3Srobert // Copy desired into target
456*810390e3Srobert dst = target;
457*810390e3Srobert src = desired;
458*810390e3Srobert } else {
459*810390e3Srobert // Copy target into expected
460*810390e3Srobert dst = expected;
461*810390e3Srobert src = target;
462*810390e3Srobert }
463*810390e3Srobert if (src == dst)
464*810390e3Srobert return;
465*810390e3Srobert CopyShadow(dst, src, size);
466*810390e3Srobert if (dfsan_get_track_origins()) {
467*810390e3Srobert // Duplicating code instead of calling __dfsan_mem_origin_transfer
468*810390e3Srobert // so that the getting the caller stack frame works correctly.
469*810390e3Srobert GET_CALLER_PC_BP;
470*810390e3Srobert GET_STORE_STACK_TRACE_PC_BP(pc, bp);
471*810390e3Srobert MoveOrigin(dst, src, size, &stack);
472*810390e3Srobert }
473*810390e3Srobert }
474*810390e3Srobert
475d89ec533Spatrick namespace __dfsan {
476d89ec533Spatrick
477d89ec533Spatrick bool dfsan_inited = false;
478d89ec533Spatrick bool dfsan_init_is_running = false;
479d89ec533Spatrick
dfsan_copy_memory(void * dst,const void * src,uptr size)480d89ec533Spatrick void dfsan_copy_memory(void *dst, const void *src, uptr size) {
481d89ec533Spatrick internal_memcpy(dst, src, size);
482*810390e3Srobert dfsan_mem_shadow_transfer(dst, src, size);
483d89ec533Spatrick if (dfsan_get_track_origins())
484d89ec533Spatrick dfsan_mem_origin_transfer(dst, src, size);
485d89ec533Spatrick }
486d89ec533Spatrick
487d89ec533Spatrick // Releases the pages within the origin address range.
ReleaseOrigins(void * addr,uptr size)488d89ec533Spatrick static void ReleaseOrigins(void *addr, uptr size) {
489d89ec533Spatrick const uptr beg_origin_addr = (uptr)__dfsan::origin_for(addr);
490d89ec533Spatrick const void *end_addr = (void *)((uptr)addr + size);
491d89ec533Spatrick const uptr end_origin_addr = (uptr)__dfsan::origin_for(end_addr);
492d89ec533Spatrick
493d89ec533Spatrick if (end_origin_addr - beg_origin_addr <
494d89ec533Spatrick common_flags()->clear_shadow_mmap_threshold)
495d89ec533Spatrick return;
496d89ec533Spatrick
497d89ec533Spatrick const uptr page_size = GetPageSizeCached();
498d89ec533Spatrick const uptr beg_aligned = RoundUpTo(beg_origin_addr, page_size);
499d89ec533Spatrick const uptr end_aligned = RoundDownTo(end_origin_addr, page_size);
500d89ec533Spatrick
501d89ec533Spatrick if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
502d89ec533Spatrick Die();
503d89ec533Spatrick }
504d89ec533Spatrick
WriteZeroShadowInRange(uptr beg,uptr end)505*810390e3Srobert static void WriteZeroShadowInRange(uptr beg, uptr end) {
506*810390e3Srobert // Don't write the label if it is already the value we need it to be.
507*810390e3Srobert // In a program where most addresses are not labeled, it is common that
508*810390e3Srobert // a page of shadow memory is entirely zeroed. The Linux copy-on-write
509*810390e3Srobert // implementation will share all of the zeroed pages, making a copy of a
510*810390e3Srobert // page when any value is written. The un-sharing will happen even if
511*810390e3Srobert // the value written does not change the value in memory. Avoiding the
512*810390e3Srobert // write when both |label| and |*labelp| are zero dramatically reduces
513*810390e3Srobert // the amount of real memory used by large programs.
514*810390e3Srobert if (!mem_is_zero((const char *)beg, end - beg))
515*810390e3Srobert internal_memset((void *)beg, 0, end - beg);
516*810390e3Srobert }
517*810390e3Srobert
518d89ec533Spatrick // Releases the pages within the shadow address range, and sets
519d89ec533Spatrick // the shadow addresses not on the pages to be 0.
ReleaseOrClearShadows(void * addr,uptr size)520d89ec533Spatrick static void ReleaseOrClearShadows(void *addr, uptr size) {
521d89ec533Spatrick const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
522d89ec533Spatrick const void *end_addr = (void *)((uptr)addr + size);
523d89ec533Spatrick const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr);
524d89ec533Spatrick
525d89ec533Spatrick if (end_shadow_addr - beg_shadow_addr <
526*810390e3Srobert common_flags()->clear_shadow_mmap_threshold) {
527*810390e3Srobert WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
528*810390e3Srobert return;
529*810390e3Srobert }
530d89ec533Spatrick
531d89ec533Spatrick const uptr page_size = GetPageSizeCached();
532d89ec533Spatrick const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size);
533d89ec533Spatrick const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size);
534d89ec533Spatrick
535d89ec533Spatrick if (beg_aligned >= end_aligned) {
536*810390e3Srobert WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);
537d89ec533Spatrick } else {
538d89ec533Spatrick if (beg_aligned != beg_shadow_addr)
539*810390e3Srobert WriteZeroShadowInRange(beg_shadow_addr, beg_aligned);
540d89ec533Spatrick if (end_aligned != end_shadow_addr)
541*810390e3Srobert WriteZeroShadowInRange(end_aligned, end_shadow_addr);
542d89ec533Spatrick if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))
543d89ec533Spatrick Die();
544d89ec533Spatrick }
545d89ec533Spatrick }
546d89ec533Spatrick
SetShadow(dfsan_label label,void * addr,uptr size,dfsan_origin origin)547d89ec533Spatrick void SetShadow(dfsan_label label, void *addr, uptr size, dfsan_origin origin) {
548d89ec533Spatrick if (0 != label) {
549d89ec533Spatrick const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);
550*810390e3Srobert internal_memset((void *)beg_shadow_addr, label, size);
551d89ec533Spatrick if (dfsan_get_track_origins())
552d89ec533Spatrick SetOrigin(addr, size, origin);
553d89ec533Spatrick return;
554d89ec533Spatrick }
555d89ec533Spatrick
556d89ec533Spatrick if (dfsan_get_track_origins())
557d89ec533Spatrick ReleaseOrigins(addr, size);
558d89ec533Spatrick
559d89ec533Spatrick ReleaseOrClearShadows(addr, size);
560d89ec533Spatrick }
561d89ec533Spatrick
562*810390e3Srobert } // namespace __dfsan
563*810390e3Srobert
564*810390e3Srobert // If the label s is tainted, set the size bytes from the address p to be a new
565*810390e3Srobert // origin chain with the previous ID o and the current stack trace. This is
566*810390e3Srobert // used by instrumentation to reduce code size when too much code is inserted.
__dfsan_maybe_store_origin(dfsan_label s,void * p,uptr size,dfsan_origin o)567*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin(
568*810390e3Srobert dfsan_label s, void *p, uptr size, dfsan_origin o) {
569*810390e3Srobert if (UNLIKELY(s)) {
570*810390e3Srobert GET_CALLER_PC_BP_SP;
571*810390e3Srobert (void)sp;
572*810390e3Srobert GET_STORE_STACK_TRACE_PC_BP(pc, bp);
573*810390e3Srobert SetOrigin(p, size, ChainOrigin(o, &stack));
574*810390e3Srobert }
575*810390e3Srobert }
576*810390e3Srobert
__dfsan_set_label(dfsan_label label,dfsan_origin origin,void * addr,uptr size)577d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(
578d89ec533Spatrick dfsan_label label, dfsan_origin origin, void *addr, uptr size) {
579*810390e3Srobert __dfsan::SetShadow(label, addr, size, origin);
580d89ec533Spatrick }
581d89ec533Spatrick
5823cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
dfsan_set_label(dfsan_label label,void * addr,uptr size)5833cab2bb3Spatrick void dfsan_set_label(dfsan_label label, void *addr, uptr size) {
584d89ec533Spatrick dfsan_origin init_origin = 0;
585d89ec533Spatrick if (label && dfsan_get_track_origins()) {
586d89ec533Spatrick GET_CALLER_PC_BP;
587d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp);
588d89ec533Spatrick init_origin = ChainOrigin(0, &stack, true);
589d89ec533Spatrick }
590*810390e3Srobert __dfsan::SetShadow(label, addr, size, init_origin);
5913cab2bb3Spatrick }
5923cab2bb3Spatrick
5933cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
dfsan_add_label(dfsan_label label,void * addr,uptr size)5943cab2bb3Spatrick void dfsan_add_label(dfsan_label label, void *addr, uptr size) {
595d89ec533Spatrick if (0 == label)
596d89ec533Spatrick return;
597d89ec533Spatrick
598d89ec533Spatrick if (dfsan_get_track_origins()) {
599d89ec533Spatrick GET_CALLER_PC_BP;
600d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp);
601d89ec533Spatrick dfsan_origin init_origin = ChainOrigin(0, &stack, true);
602d89ec533Spatrick SetOrigin(addr, size, init_origin);
603d89ec533Spatrick }
604d89ec533Spatrick
6053cab2bb3Spatrick for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)
606d89ec533Spatrick *labelp |= label;
6073cab2bb3Spatrick }
6083cab2bb3Spatrick
6093cab2bb3Spatrick // Unlike the other dfsan interface functions the behavior of this function
6103cab2bb3Spatrick // depends on the label of one of its arguments. Hence it is implemented as a
6113cab2bb3Spatrick // custom function.
6123cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
__dfsw_dfsan_get_label(long data,dfsan_label data_label,dfsan_label * ret_label)6133cab2bb3Spatrick __dfsw_dfsan_get_label(long data, dfsan_label data_label,
6143cab2bb3Spatrick dfsan_label *ret_label) {
6153cab2bb3Spatrick *ret_label = 0;
6163cab2bb3Spatrick return data_label;
6173cab2bb3Spatrick }
6183cab2bb3Spatrick
__dfso_dfsan_get_label(long data,dfsan_label data_label,dfsan_label * ret_label,dfsan_origin data_origin,dfsan_origin * ret_origin)619d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfso_dfsan_get_label(
620d89ec533Spatrick long data, dfsan_label data_label, dfsan_label *ret_label,
621d89ec533Spatrick dfsan_origin data_origin, dfsan_origin *ret_origin) {
622d89ec533Spatrick *ret_label = 0;
623d89ec533Spatrick *ret_origin = 0;
624d89ec533Spatrick return data_label;
625d89ec533Spatrick }
626d89ec533Spatrick
627d89ec533Spatrick // This function is used if dfsan_get_origin is called when origin tracking is
628d89ec533Spatrick // off.
__dfsw_dfsan_get_origin(long data,dfsan_label data_label,dfsan_label * ret_label)629d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfsw_dfsan_get_origin(
630d89ec533Spatrick long data, dfsan_label data_label, dfsan_label *ret_label) {
631d89ec533Spatrick *ret_label = 0;
632d89ec533Spatrick return 0;
633d89ec533Spatrick }
634d89ec533Spatrick
__dfso_dfsan_get_origin(long data,dfsan_label data_label,dfsan_label * ret_label,dfsan_origin data_origin,dfsan_origin * ret_origin)635d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfso_dfsan_get_origin(
636d89ec533Spatrick long data, dfsan_label data_label, dfsan_label *ret_label,
637d89ec533Spatrick dfsan_origin data_origin, dfsan_origin *ret_origin) {
638d89ec533Spatrick *ret_label = 0;
639d89ec533Spatrick *ret_origin = 0;
640d89ec533Spatrick return data_origin;
641d89ec533Spatrick }
642d89ec533Spatrick
6433cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
dfsan_read_label(const void * addr,uptr size)6443cab2bb3Spatrick dfsan_read_label(const void *addr, uptr size) {
6453cab2bb3Spatrick if (size == 0)
6463cab2bb3Spatrick return 0;
6473cab2bb3Spatrick return __dfsan_union_load(shadow_for(addr), size);
6483cab2bb3Spatrick }
6493cab2bb3Spatrick
650d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
dfsan_read_origin_of_first_taint(const void * addr,uptr size)651d89ec533Spatrick dfsan_read_origin_of_first_taint(const void *addr, uptr size) {
652d89ec533Spatrick return GetOriginIfTainted((uptr)addr, size);
653d89ec533Spatrick }
654d89ec533Spatrick
dfsan_set_label_origin(dfsan_label label,dfsan_origin origin,void * addr,uptr size)655d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label_origin(dfsan_label label,
656d89ec533Spatrick dfsan_origin origin,
657d89ec533Spatrick void *addr,
658d89ec533Spatrick uptr size) {
659d89ec533Spatrick __dfsan_set_label(label, origin, addr, size);
6603cab2bb3Spatrick }
6613cab2bb3Spatrick
6623cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE int
dfsan_has_label(dfsan_label label,dfsan_label elem)6633cab2bb3Spatrick dfsan_has_label(dfsan_label label, dfsan_label elem) {
664d89ec533Spatrick return (label & elem) == elem;
6653cab2bb3Spatrick }
6663cab2bb3Spatrick
667*810390e3Srobert namespace __dfsan {
668*810390e3Srobert
669*810390e3Srobert typedef void (*dfsan_conditional_callback_t)(dfsan_label label,
670*810390e3Srobert dfsan_origin origin);
671*810390e3Srobert static dfsan_conditional_callback_t conditional_callback = nullptr;
672*810390e3Srobert static dfsan_label labels_in_signal_conditional = 0;
673*810390e3Srobert
ConditionalCallback(dfsan_label label,dfsan_origin origin)674*810390e3Srobert static void ConditionalCallback(dfsan_label label, dfsan_origin origin) {
675*810390e3Srobert // Programs have many branches. For efficiency the conditional sink callback
676*810390e3Srobert // handler needs to ignore as many as possible as early as possible.
677*810390e3Srobert if (label == 0) {
678*810390e3Srobert return;
679*810390e3Srobert }
680*810390e3Srobert if (conditional_callback == nullptr) {
681*810390e3Srobert return;
682*810390e3Srobert }
683*810390e3Srobert
684*810390e3Srobert // This initial ConditionalCallback handler needs to be in here in dfsan
685*810390e3Srobert // runtime (rather than being an entirely user implemented hook) so that it
686*810390e3Srobert // has access to dfsan thread information.
687*810390e3Srobert DFsanThread *t = GetCurrentThread();
688*810390e3Srobert // A callback operation which does useful work (like record the flow) will
689*810390e3Srobert // likely be too long executed in a signal handler.
690*810390e3Srobert if (t && t->InSignalHandler()) {
691*810390e3Srobert // Record set of labels used in signal handler for completeness.
692*810390e3Srobert labels_in_signal_conditional |= label;
693*810390e3Srobert return;
694*810390e3Srobert }
695*810390e3Srobert
696*810390e3Srobert conditional_callback(label, origin);
697*810390e3Srobert }
698*810390e3Srobert
699*810390e3Srobert } // namespace __dfsan
700*810390e3Srobert
701*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__dfsan_conditional_callback_origin(dfsan_label label,dfsan_origin origin)702*810390e3Srobert __dfsan_conditional_callback_origin(dfsan_label label, dfsan_origin origin) {
703*810390e3Srobert __dfsan::ConditionalCallback(label, origin);
704*810390e3Srobert }
705*810390e3Srobert
__dfsan_conditional_callback(dfsan_label label)706*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_conditional_callback(
707*810390e3Srobert dfsan_label label) {
708*810390e3Srobert __dfsan::ConditionalCallback(label, 0);
709*810390e3Srobert }
710*810390e3Srobert
dfsan_set_conditional_callback(__dfsan::dfsan_conditional_callback_t callback)711*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_conditional_callback(
712*810390e3Srobert __dfsan::dfsan_conditional_callback_t callback) {
713*810390e3Srobert __dfsan::conditional_callback = callback;
714*810390e3Srobert }
715*810390e3Srobert
716*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
dfsan_get_labels_in_signal_conditional()717*810390e3Srobert dfsan_get_labels_in_signal_conditional() {
718*810390e3Srobert return __dfsan::labels_in_signal_conditional;
719*810390e3Srobert }
720*810390e3Srobert
721*810390e3Srobert namespace __dfsan {
722*810390e3Srobert
723*810390e3Srobert typedef void (*dfsan_reaches_function_callback_t)(dfsan_label label,
724*810390e3Srobert dfsan_origin origin,
725*810390e3Srobert const char *file,
726*810390e3Srobert unsigned int line,
727*810390e3Srobert const char *function);
728*810390e3Srobert static dfsan_reaches_function_callback_t reaches_function_callback = nullptr;
729*810390e3Srobert static dfsan_label labels_in_signal_reaches_function = 0;
730*810390e3Srobert
ReachesFunctionCallback(dfsan_label label,dfsan_origin origin,const char * file,unsigned int line,const char * function)731*810390e3Srobert static void ReachesFunctionCallback(dfsan_label label, dfsan_origin origin,
732*810390e3Srobert const char *file, unsigned int line,
733*810390e3Srobert const char *function) {
734*810390e3Srobert if (label == 0) {
735*810390e3Srobert return;
736*810390e3Srobert }
737*810390e3Srobert if (reaches_function_callback == nullptr) {
738*810390e3Srobert return;
739*810390e3Srobert }
740*810390e3Srobert
741*810390e3Srobert // This initial ReachesFunctionCallback handler needs to be in here in dfsan
742*810390e3Srobert // runtime (rather than being an entirely user implemented hook) so that it
743*810390e3Srobert // has access to dfsan thread information.
744*810390e3Srobert DFsanThread *t = GetCurrentThread();
745*810390e3Srobert // A callback operation which does useful work (like record the flow) will
746*810390e3Srobert // likely be too long executed in a signal handler.
747*810390e3Srobert if (t && t->InSignalHandler()) {
748*810390e3Srobert // Record set of labels used in signal handler for completeness.
749*810390e3Srobert labels_in_signal_reaches_function |= label;
750*810390e3Srobert return;
751*810390e3Srobert }
752*810390e3Srobert
753*810390e3Srobert reaches_function_callback(label, origin, file, line, function);
754*810390e3Srobert }
755*810390e3Srobert
756*810390e3Srobert } // namespace __dfsan
757*810390e3Srobert
758*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__dfsan_reaches_function_callback_origin(dfsan_label label,dfsan_origin origin,const char * file,unsigned int line,const char * function)759*810390e3Srobert __dfsan_reaches_function_callback_origin(dfsan_label label, dfsan_origin origin,
760*810390e3Srobert const char *file, unsigned int line,
761*810390e3Srobert const char *function) {
762*810390e3Srobert __dfsan::ReachesFunctionCallback(label, origin, file, line, function);
763*810390e3Srobert }
764*810390e3Srobert
765*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__dfsan_reaches_function_callback(dfsan_label label,const char * file,unsigned int line,const char * function)766*810390e3Srobert __dfsan_reaches_function_callback(dfsan_label label, const char *file,
767*810390e3Srobert unsigned int line, const char *function) {
768*810390e3Srobert __dfsan::ReachesFunctionCallback(label, 0, file, line, function);
769*810390e3Srobert }
770*810390e3Srobert
771*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
dfsan_set_reaches_function_callback(__dfsan::dfsan_reaches_function_callback_t callback)772*810390e3Srobert dfsan_set_reaches_function_callback(
773*810390e3Srobert __dfsan::dfsan_reaches_function_callback_t callback) {
774*810390e3Srobert __dfsan::reaches_function_callback = callback;
775*810390e3Srobert }
776*810390e3Srobert
777*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label
dfsan_get_labels_in_signal_reaches_function()778*810390e3Srobert dfsan_get_labels_in_signal_reaches_function() {
779*810390e3Srobert return __dfsan::labels_in_signal_reaches_function;
780*810390e3Srobert }
781*810390e3Srobert
782d89ec533Spatrick class Decorator : public __sanitizer::SanitizerCommonDecorator {
783d89ec533Spatrick public:
Decorator()784d89ec533Spatrick Decorator() : SanitizerCommonDecorator() {}
Origin() const785d89ec533Spatrick const char *Origin() const { return Magenta(); }
786d89ec533Spatrick };
787d89ec533Spatrick
788d89ec533Spatrick namespace {
789d89ec533Spatrick
PrintNoOriginTrackingWarning()790d89ec533Spatrick void PrintNoOriginTrackingWarning() {
791d89ec533Spatrick Decorator d;
792d89ec533Spatrick Printf(
793d89ec533Spatrick " %sDFSan: origin tracking is not enabled. Did you specify the "
794d89ec533Spatrick "-dfsan-track-origins=1 option?%s\n",
795d89ec533Spatrick d.Warning(), d.Default());
7963cab2bb3Spatrick }
7973cab2bb3Spatrick
PrintNoTaintWarning(const void * address)798d89ec533Spatrick void PrintNoTaintWarning(const void *address) {
799d89ec533Spatrick Decorator d;
800d89ec533Spatrick Printf(" %sDFSan: no tainted value at %x%s\n", d.Warning(), address,
801d89ec533Spatrick d.Default());
8023cab2bb3Spatrick }
8033cab2bb3Spatrick
PrintInvalidOriginWarning(dfsan_label label,const void * address)804d89ec533Spatrick void PrintInvalidOriginWarning(dfsan_label label, const void *address) {
805d89ec533Spatrick Decorator d;
806d89ec533Spatrick Printf(
807d89ec533Spatrick " %sTaint value 0x%x (at %p) has invalid origin tracking. This can "
808d89ec533Spatrick "be a DFSan bug.%s\n",
809d89ec533Spatrick d.Warning(), label, address, d.Default());
810d89ec533Spatrick }
8113cab2bb3Spatrick
PrintInvalidOriginIdWarning(dfsan_origin origin)812*810390e3Srobert void PrintInvalidOriginIdWarning(dfsan_origin origin) {
813d89ec533Spatrick Decorator d;
814*810390e3Srobert Printf(
815*810390e3Srobert " %sOrigin Id %d has invalid origin tracking. This can "
816*810390e3Srobert "be a DFSan bug.%s\n",
817*810390e3Srobert d.Warning(), origin, d.Default());
818*810390e3Srobert }
819d89ec533Spatrick
PrintOriginTraceFramesToStr(Origin o,InternalScopedString * out)820*810390e3Srobert bool PrintOriginTraceFramesToStr(Origin o, InternalScopedString *out) {
821*810390e3Srobert Decorator d;
822d89ec533Spatrick bool found = false;
823d89ec533Spatrick
824d89ec533Spatrick while (o.isChainedOrigin()) {
825d89ec533Spatrick StackTrace stack;
826d89ec533Spatrick dfsan_origin origin_id = o.raw_id();
827d89ec533Spatrick o = o.getNextChainedOrigin(&stack);
828d89ec533Spatrick if (o.isChainedOrigin())
829d89ec533Spatrick out->append(
830d89ec533Spatrick " %sOrigin value: 0x%x, Taint value was stored to memory at%s\n",
831d89ec533Spatrick d.Origin(), origin_id, d.Default());
832d89ec533Spatrick else
833d89ec533Spatrick out->append(" %sOrigin value: 0x%x, Taint value was created at%s\n",
834d89ec533Spatrick d.Origin(), origin_id, d.Default());
835d89ec533Spatrick
836d89ec533Spatrick // Includes a trailing newline, so no need to add it again.
837d89ec533Spatrick stack.PrintTo(out);
838d89ec533Spatrick found = true;
8393cab2bb3Spatrick }
840d89ec533Spatrick
841d89ec533Spatrick return found;
8423cab2bb3Spatrick }
843d89ec533Spatrick
PrintOriginTraceToStr(const void * addr,const char * description,InternalScopedString * out)844*810390e3Srobert bool PrintOriginTraceToStr(const void *addr, const char *description,
845*810390e3Srobert InternalScopedString *out) {
846*810390e3Srobert CHECK(out);
847*810390e3Srobert CHECK(dfsan_get_track_origins());
848*810390e3Srobert Decorator d;
849*810390e3Srobert
850*810390e3Srobert const dfsan_label label = *__dfsan::shadow_for(addr);
851*810390e3Srobert CHECK(label);
852*810390e3Srobert
853*810390e3Srobert const dfsan_origin origin = *__dfsan::origin_for(addr);
854*810390e3Srobert
855*810390e3Srobert out->append(" %sTaint value 0x%x (at %p) origin tracking (%s)%s\n",
856*810390e3Srobert d.Origin(), label, addr, description ? description : "",
857*810390e3Srobert d.Default());
858*810390e3Srobert
859*810390e3Srobert Origin o = Origin::FromRawId(origin);
860*810390e3Srobert return PrintOriginTraceFramesToStr(o, out);
861*810390e3Srobert }
862*810390e3Srobert
863d89ec533Spatrick } // namespace
864d89ec533Spatrick
dfsan_print_origin_trace(const void * addr,const char * description)865d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace(
866d89ec533Spatrick const void *addr, const char *description) {
867d89ec533Spatrick if (!dfsan_get_track_origins()) {
868d89ec533Spatrick PrintNoOriginTrackingWarning();
869d89ec533Spatrick return;
870d89ec533Spatrick }
871d89ec533Spatrick
872d89ec533Spatrick const dfsan_label label = *__dfsan::shadow_for(addr);
873d89ec533Spatrick if (!label) {
874d89ec533Spatrick PrintNoTaintWarning(addr);
875d89ec533Spatrick return;
876d89ec533Spatrick }
877d89ec533Spatrick
878d89ec533Spatrick InternalScopedString trace;
879d89ec533Spatrick bool success = PrintOriginTraceToStr(addr, description, &trace);
880d89ec533Spatrick
881d89ec533Spatrick if (trace.length())
882d89ec533Spatrick Printf("%s", trace.data());
883d89ec533Spatrick
884d89ec533Spatrick if (!success)
885d89ec533Spatrick PrintInvalidOriginWarning(label, addr);
886d89ec533Spatrick }
887d89ec533Spatrick
888*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
dfsan_sprint_origin_trace(const void * addr,const char * description,char * out_buf,uptr out_buf_size)889d89ec533Spatrick dfsan_sprint_origin_trace(const void *addr, const char *description,
890*810390e3Srobert char *out_buf, uptr out_buf_size) {
891d89ec533Spatrick CHECK(out_buf);
892d89ec533Spatrick
893d89ec533Spatrick if (!dfsan_get_track_origins()) {
894d89ec533Spatrick PrintNoOriginTrackingWarning();
895d89ec533Spatrick return 0;
896d89ec533Spatrick }
897d89ec533Spatrick
898d89ec533Spatrick const dfsan_label label = *__dfsan::shadow_for(addr);
899d89ec533Spatrick if (!label) {
900d89ec533Spatrick PrintNoTaintWarning(addr);
901d89ec533Spatrick return 0;
902d89ec533Spatrick }
903d89ec533Spatrick
904d89ec533Spatrick InternalScopedString trace;
905d89ec533Spatrick bool success = PrintOriginTraceToStr(addr, description, &trace);
906d89ec533Spatrick
907d89ec533Spatrick if (!success) {
908d89ec533Spatrick PrintInvalidOriginWarning(label, addr);
909d89ec533Spatrick return 0;
910d89ec533Spatrick }
911d89ec533Spatrick
912d89ec533Spatrick if (out_buf_size) {
913d89ec533Spatrick internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
914d89ec533Spatrick out_buf[out_buf_size - 1] = '\0';
915d89ec533Spatrick }
916d89ec533Spatrick
917d89ec533Spatrick return trace.length();
918d89ec533Spatrick }
919d89ec533Spatrick
dfsan_print_origin_id_trace(dfsan_origin origin)920*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_id_trace(
921*810390e3Srobert dfsan_origin origin) {
922*810390e3Srobert if (!dfsan_get_track_origins()) {
923*810390e3Srobert PrintNoOriginTrackingWarning();
924*810390e3Srobert return;
925*810390e3Srobert }
926*810390e3Srobert Origin o = Origin::FromRawId(origin);
927*810390e3Srobert
928*810390e3Srobert InternalScopedString trace;
929*810390e3Srobert bool success = PrintOriginTraceFramesToStr(o, &trace);
930*810390e3Srobert
931*810390e3Srobert if (trace.length())
932*810390e3Srobert Printf("%s", trace.data());
933*810390e3Srobert
934*810390e3Srobert if (!success)
935*810390e3Srobert PrintInvalidOriginIdWarning(origin);
936*810390e3Srobert }
937*810390e3Srobert
dfsan_sprint_origin_id_trace(dfsan_origin origin,char * out_buf,uptr out_buf_size)938*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_sprint_origin_id_trace(
939*810390e3Srobert dfsan_origin origin, char *out_buf, uptr out_buf_size) {
940*810390e3Srobert CHECK(out_buf);
941*810390e3Srobert
942*810390e3Srobert if (!dfsan_get_track_origins()) {
943*810390e3Srobert PrintNoOriginTrackingWarning();
944*810390e3Srobert return 0;
945*810390e3Srobert }
946*810390e3Srobert Origin o = Origin::FromRawId(origin);
947*810390e3Srobert
948*810390e3Srobert InternalScopedString trace;
949*810390e3Srobert bool success = PrintOriginTraceFramesToStr(o, &trace);
950*810390e3Srobert
951*810390e3Srobert if (!success) {
952*810390e3Srobert PrintInvalidOriginIdWarning(origin);
953*810390e3Srobert return 0;
954*810390e3Srobert }
955*810390e3Srobert
956*810390e3Srobert if (out_buf_size) {
957*810390e3Srobert internal_strncpy(out_buf, trace.data(), out_buf_size - 1);
958*810390e3Srobert out_buf[out_buf_size - 1] = '\0';
959*810390e3Srobert }
960*810390e3Srobert
961*810390e3Srobert return trace.length();
962*810390e3Srobert }
963*810390e3Srobert
964d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin
dfsan_get_init_origin(const void * addr)965d89ec533Spatrick dfsan_get_init_origin(const void *addr) {
966d89ec533Spatrick if (!dfsan_get_track_origins())
967d89ec533Spatrick return 0;
968d89ec533Spatrick
969d89ec533Spatrick const dfsan_label label = *__dfsan::shadow_for(addr);
970d89ec533Spatrick if (!label)
971d89ec533Spatrick return 0;
972d89ec533Spatrick
973d89ec533Spatrick const dfsan_origin origin = *__dfsan::origin_for(addr);
974d89ec533Spatrick
975d89ec533Spatrick Origin o = Origin::FromRawId(origin);
976d89ec533Spatrick dfsan_origin origin_id = o.raw_id();
977d89ec533Spatrick while (o.isChainedOrigin()) {
978d89ec533Spatrick StackTrace stack;
979d89ec533Spatrick origin_id = o.raw_id();
980d89ec533Spatrick o = o.getNextChainedOrigin(&stack);
981d89ec533Spatrick }
982d89ec533Spatrick return origin_id;
983d89ec533Spatrick }
984d89ec533Spatrick
UnwindImpl(uptr pc,uptr bp,void * context,bool request_fast,u32 max_depth)985d89ec533Spatrick void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
986d89ec533Spatrick void *context,
987d89ec533Spatrick bool request_fast,
988d89ec533Spatrick u32 max_depth) {
989d89ec533Spatrick using namespace __dfsan;
990d89ec533Spatrick DFsanThread *t = GetCurrentThread();
991d89ec533Spatrick if (!t || !StackTrace::WillUseFastUnwind(request_fast)) {
992d89ec533Spatrick return Unwind(max_depth, pc, bp, context, 0, 0, false);
993d89ec533Spatrick }
994d89ec533Spatrick Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true);
995d89ec533Spatrick }
996d89ec533Spatrick
__sanitizer_print_stack_trace()997d89ec533Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() {
998d89ec533Spatrick GET_CALLER_PC_BP;
999d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp);
1000d89ec533Spatrick stack.Print();
1001d89ec533Spatrick }
1002d89ec533Spatrick
1003*810390e3Srobert extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr
dfsan_sprint_stack_trace(char * out_buf,uptr out_buf_size)1004*810390e3Srobert dfsan_sprint_stack_trace(char *out_buf, uptr out_buf_size) {
1005d89ec533Spatrick CHECK(out_buf);
1006d89ec533Spatrick GET_CALLER_PC_BP;
1007d89ec533Spatrick GET_STORE_STACK_TRACE_PC_BP(pc, bp);
1008d89ec533Spatrick return stack.PrintTo(out_buf, out_buf_size);
10093cab2bb3Spatrick }
10103cab2bb3Spatrick
SetDefaults()10113cab2bb3Spatrick void Flags::SetDefaults() {
10123cab2bb3Spatrick #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
10133cab2bb3Spatrick #include "dfsan_flags.inc"
10143cab2bb3Spatrick #undef DFSAN_FLAG
10153cab2bb3Spatrick }
10163cab2bb3Spatrick
RegisterDfsanFlags(FlagParser * parser,Flags * f)10173cab2bb3Spatrick static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
10183cab2bb3Spatrick #define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
10193cab2bb3Spatrick RegisterFlag(parser, #Name, Description, &f->Name);
10203cab2bb3Spatrick #include "dfsan_flags.inc"
10213cab2bb3Spatrick #undef DFSAN_FLAG
10223cab2bb3Spatrick }
10233cab2bb3Spatrick
InitializeFlags()10243cab2bb3Spatrick static void InitializeFlags() {
10253cab2bb3Spatrick SetCommonFlagsDefaults();
1026d89ec533Spatrick {
1027d89ec533Spatrick CommonFlags cf;
1028d89ec533Spatrick cf.CopyFrom(*common_flags());
1029d89ec533Spatrick cf.intercept_tls_get_addr = true;
1030d89ec533Spatrick OverrideCommonFlags(cf);
1031d89ec533Spatrick }
10323cab2bb3Spatrick flags().SetDefaults();
10333cab2bb3Spatrick
10343cab2bb3Spatrick FlagParser parser;
10353cab2bb3Spatrick RegisterCommonFlags(&parser);
10363cab2bb3Spatrick RegisterDfsanFlags(&parser, &flags());
10373cab2bb3Spatrick parser.ParseStringFromEnv("DFSAN_OPTIONS");
10383cab2bb3Spatrick InitializeCommonFlags();
10393cab2bb3Spatrick if (Verbosity()) ReportUnrecognizedFlags();
10403cab2bb3Spatrick if (common_flags()->help) parser.PrintFlagDescriptions();
10413cab2bb3Spatrick }
10423cab2bb3Spatrick
1043d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE
dfsan_clear_arg_tls(uptr offset,uptr size)1044d89ec533Spatrick void dfsan_clear_arg_tls(uptr offset, uptr size) {
1045d89ec533Spatrick internal_memset((void *)((uptr)__dfsan_arg_tls + offset), 0, size);
10463cab2bb3Spatrick }
10473cab2bb3Spatrick
1048d89ec533Spatrick SANITIZER_INTERFACE_ATTRIBUTE
dfsan_clear_thread_local_state()1049d89ec533Spatrick void dfsan_clear_thread_local_state() {
1050d89ec533Spatrick internal_memset(__dfsan_arg_tls, 0, sizeof(__dfsan_arg_tls));
1051d89ec533Spatrick internal_memset(__dfsan_retval_tls, 0, sizeof(__dfsan_retval_tls));
10523cab2bb3Spatrick
1053d89ec533Spatrick if (dfsan_get_track_origins()) {
1054d89ec533Spatrick internal_memset(__dfsan_arg_origin_tls, 0, sizeof(__dfsan_arg_origin_tls));
1055d89ec533Spatrick internal_memset(&__dfsan_retval_origin_tls, 0,
1056d89ec533Spatrick sizeof(__dfsan_retval_origin_tls));
10573cab2bb3Spatrick }
10583cab2bb3Spatrick }
10593cab2bb3Spatrick
1060*810390e3Srobert SANITIZER_INTERFACE_ATTRIBUTE
dfsan_set_arg_tls(uptr offset,dfsan_label label)1061*810390e3Srobert void dfsan_set_arg_tls(uptr offset, dfsan_label label) {
1062*810390e3Srobert // 2x to match ShadowTLSAlignment.
1063*810390e3Srobert // ShadowTLSAlignment should probably be changed.
1064*810390e3Srobert // TODO: Consider reducing ShadowTLSAlignment to 1.
1065*810390e3Srobert // Aligning to 2 bytes is probably a remnant of fast16 mode.
1066*810390e3Srobert ((dfsan_label *)__dfsan_arg_tls)[offset * 2] = label;
1067*810390e3Srobert }
1068*810390e3Srobert
1069*810390e3Srobert SANITIZER_INTERFACE_ATTRIBUTE
dfsan_set_arg_origin_tls(uptr offset,dfsan_origin o)1070*810390e3Srobert void dfsan_set_arg_origin_tls(uptr offset, dfsan_origin o) {
1071*810390e3Srobert __dfsan_arg_origin_tls[offset] = o;
1072*810390e3Srobert }
1073*810390e3Srobert
dfsan_flush()10743cab2bb3Spatrick extern "C" void dfsan_flush() {
1075d89ec533Spatrick const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
1076d89ec533Spatrick for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
1077d89ec533Spatrick uptr start = kMemoryLayout[i].start;
1078d89ec533Spatrick uptr end = kMemoryLayout[i].end;
1079d89ec533Spatrick uptr size = end - start;
1080d89ec533Spatrick MappingDesc::Type type = kMemoryLayout[i].type;
1081d89ec533Spatrick
1082d89ec533Spatrick if (type != MappingDesc::SHADOW && type != MappingDesc::ORIGIN)
1083d89ec533Spatrick continue;
1084d89ec533Spatrick
1085d89ec533Spatrick // Check if the segment should be mapped based on platform constraints.
1086d89ec533Spatrick if (start >= maxVirtualAddress)
1087d89ec533Spatrick continue;
1088d89ec533Spatrick
1089d89ec533Spatrick if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) {
1090d89ec533Spatrick Printf("FATAL: DataFlowSanitizer: failed to clear memory region\n");
10913cab2bb3Spatrick Die();
10923cab2bb3Spatrick }
1093d89ec533Spatrick }
1094*810390e3Srobert __dfsan::labels_in_signal_conditional = 0;
1095*810390e3Srobert __dfsan::labels_in_signal_reaches_function = 0;
1096d89ec533Spatrick }
10973cab2bb3Spatrick
1098d89ec533Spatrick // TODO: CheckMemoryLayoutSanity is based on msan.
1099d89ec533Spatrick // Consider refactoring these into a shared implementation.
CheckMemoryLayoutSanity()1100d89ec533Spatrick static void CheckMemoryLayoutSanity() {
1101d89ec533Spatrick uptr prev_end = 0;
1102d89ec533Spatrick for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
1103d89ec533Spatrick uptr start = kMemoryLayout[i].start;
1104d89ec533Spatrick uptr end = kMemoryLayout[i].end;
1105d89ec533Spatrick MappingDesc::Type type = kMemoryLayout[i].type;
1106d89ec533Spatrick CHECK_LT(start, end);
1107d89ec533Spatrick CHECK_EQ(prev_end, start);
1108d89ec533Spatrick CHECK(addr_is_type(start, type));
1109d89ec533Spatrick CHECK(addr_is_type((start + end) / 2, type));
1110d89ec533Spatrick CHECK(addr_is_type(end - 1, type));
1111d89ec533Spatrick if (type == MappingDesc::APP) {
1112d89ec533Spatrick uptr addr = start;
1113d89ec533Spatrick CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
1114d89ec533Spatrick CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
1115d89ec533Spatrick CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
1116d89ec533Spatrick
1117d89ec533Spatrick addr = (start + end) / 2;
1118d89ec533Spatrick CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
1119d89ec533Spatrick CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
1120d89ec533Spatrick CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
1121d89ec533Spatrick
1122d89ec533Spatrick addr = end - 1;
1123d89ec533Spatrick CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));
1124d89ec533Spatrick CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));
1125d89ec533Spatrick CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));
1126d89ec533Spatrick }
1127d89ec533Spatrick prev_end = end;
1128d89ec533Spatrick }
1129d89ec533Spatrick }
1130d89ec533Spatrick
1131d89ec533Spatrick // TODO: CheckMemoryRangeAvailability is based on msan.
1132d89ec533Spatrick // Consider refactoring these into a shared implementation.
CheckMemoryRangeAvailability(uptr beg,uptr size)1133d89ec533Spatrick static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
1134d89ec533Spatrick if (size > 0) {
1135d89ec533Spatrick uptr end = beg + size - 1;
1136d89ec533Spatrick if (!MemoryRangeIsAvailable(beg, end)) {
1137d89ec533Spatrick Printf("FATAL: Memory range %p - %p is not available.\n", beg, end);
1138d89ec533Spatrick return false;
1139d89ec533Spatrick }
1140d89ec533Spatrick }
1141d89ec533Spatrick return true;
1142d89ec533Spatrick }
1143d89ec533Spatrick
1144d89ec533Spatrick // TODO: ProtectMemoryRange is based on msan.
1145d89ec533Spatrick // Consider refactoring these into a shared implementation.
ProtectMemoryRange(uptr beg,uptr size,const char * name)1146d89ec533Spatrick static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {
1147d89ec533Spatrick if (size > 0) {
1148d89ec533Spatrick void *addr = MmapFixedNoAccess(beg, size, name);
1149d89ec533Spatrick if (beg == 0 && addr) {
1150d89ec533Spatrick // Depending on the kernel configuration, we may not be able to protect
1151d89ec533Spatrick // the page at address zero.
1152d89ec533Spatrick uptr gap = 16 * GetPageSizeCached();
1153d89ec533Spatrick beg += gap;
1154d89ec533Spatrick size -= gap;
1155d89ec533Spatrick addr = MmapFixedNoAccess(beg, size, name);
1156d89ec533Spatrick }
1157d89ec533Spatrick if ((uptr)addr != beg) {
1158d89ec533Spatrick uptr end = beg + size - 1;
1159d89ec533Spatrick Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", beg, end,
1160d89ec533Spatrick name);
1161d89ec533Spatrick return false;
1162d89ec533Spatrick }
1163d89ec533Spatrick }
1164d89ec533Spatrick return true;
1165d89ec533Spatrick }
1166d89ec533Spatrick
1167d89ec533Spatrick // TODO: InitShadow is based on msan.
1168d89ec533Spatrick // Consider refactoring these into a shared implementation.
InitShadow(bool init_origins)1169d89ec533Spatrick bool InitShadow(bool init_origins) {
1170d89ec533Spatrick // Let user know mapping parameters first.
1171*810390e3Srobert VPrintf(1, "dfsan_init %p\n", (void *)&__dfsan::dfsan_init);
1172d89ec533Spatrick for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
1173d89ec533Spatrick VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,
1174d89ec533Spatrick kMemoryLayout[i].end - 1);
1175d89ec533Spatrick
1176d89ec533Spatrick CheckMemoryLayoutSanity();
1177d89ec533Spatrick
1178d89ec533Spatrick if (!MEM_IS_APP(&__dfsan::dfsan_init)) {
1179d89ec533Spatrick Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",
1180d89ec533Spatrick (uptr)&__dfsan::dfsan_init);
1181d89ec533Spatrick return false;
1182d89ec533Spatrick }
1183d89ec533Spatrick
1184d89ec533Spatrick const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
1185d89ec533Spatrick
1186d89ec533Spatrick for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
1187d89ec533Spatrick uptr start = kMemoryLayout[i].start;
1188d89ec533Spatrick uptr end = kMemoryLayout[i].end;
1189d89ec533Spatrick uptr size = end - start;
1190d89ec533Spatrick MappingDesc::Type type = kMemoryLayout[i].type;
1191d89ec533Spatrick
1192d89ec533Spatrick // Check if the segment should be mapped based on platform constraints.
1193d89ec533Spatrick if (start >= maxVirtualAddress)
1194d89ec533Spatrick continue;
1195d89ec533Spatrick
1196d89ec533Spatrick bool map = type == MappingDesc::SHADOW ||
1197d89ec533Spatrick (init_origins && type == MappingDesc::ORIGIN);
1198d89ec533Spatrick bool protect = type == MappingDesc::INVALID ||
1199d89ec533Spatrick (!init_origins && type == MappingDesc::ORIGIN);
1200d89ec533Spatrick CHECK(!(map && protect));
1201d89ec533Spatrick if (!map && !protect)
1202d89ec533Spatrick CHECK(type == MappingDesc::APP);
1203d89ec533Spatrick if (map) {
1204d89ec533Spatrick if (!CheckMemoryRangeAvailability(start, size))
1205d89ec533Spatrick return false;
1206d89ec533Spatrick if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))
1207d89ec533Spatrick return false;
1208d89ec533Spatrick if (common_flags()->use_madv_dontdump)
1209d89ec533Spatrick DontDumpShadowMemory(start, size);
1210d89ec533Spatrick }
1211d89ec533Spatrick if (protect) {
1212d89ec533Spatrick if (!CheckMemoryRangeAvailability(start, size))
1213d89ec533Spatrick return false;
1214d89ec533Spatrick if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
1215d89ec533Spatrick return false;
1216d89ec533Spatrick }
1217d89ec533Spatrick }
1218d89ec533Spatrick
1219d89ec533Spatrick return true;
1220d89ec533Spatrick }
1221d89ec533Spatrick
DFsanInit(int argc,char ** argv,char ** envp)1222d89ec533Spatrick static void DFsanInit(int argc, char **argv, char **envp) {
1223d89ec533Spatrick CHECK(!dfsan_init_is_running);
1224d89ec533Spatrick if (dfsan_inited)
1225d89ec533Spatrick return;
1226d89ec533Spatrick dfsan_init_is_running = true;
1227d89ec533Spatrick SanitizerToolName = "DataflowSanitizer";
1228d89ec533Spatrick
1229d89ec533Spatrick AvoidCVE_2016_2143();
1230d89ec533Spatrick
12313cab2bb3Spatrick InitializeFlags();
12323cab2bb3Spatrick
1233d89ec533Spatrick CheckASLR();
12343cab2bb3Spatrick
1235d89ec533Spatrick InitShadow(dfsan_get_track_origins());
12363cab2bb3Spatrick
1237d89ec533Spatrick initialize_interceptors();
12383cab2bb3Spatrick
1239d89ec533Spatrick // Set up threads
1240d89ec533Spatrick DFsanTSDInit(DFsanTSDDtor);
12413cab2bb3Spatrick
1242d89ec533Spatrick dfsan_allocator_init();
12433cab2bb3Spatrick
1244*810390e3Srobert DFsanThread *main_thread = DFsanThread::Create(nullptr, nullptr);
1245d89ec533Spatrick SetCurrentThread(main_thread);
1246*810390e3Srobert main_thread->Init();
1247d89ec533Spatrick
1248d89ec533Spatrick dfsan_init_is_running = false;
1249d89ec533Spatrick dfsan_inited = true;
12503cab2bb3Spatrick }
12513cab2bb3Spatrick
1252d89ec533Spatrick namespace __dfsan {
1253d89ec533Spatrick
dfsan_init()1254d89ec533Spatrick void dfsan_init() { DFsanInit(0, nullptr, nullptr); }
1255d89ec533Spatrick
1256d89ec533Spatrick } // namespace __dfsan
1257d89ec533Spatrick
12583cab2bb3Spatrick #if SANITIZER_CAN_USE_PREINIT_ARRAY
1259d89ec533Spatrick __attribute__((section(".preinit_array"),
1260d89ec533Spatrick used)) static void (*dfsan_init_ptr)(int, char **,
1261d89ec533Spatrick char **) = DFsanInit;
12623cab2bb3Spatrick #endif
1263