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