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