1296 lines · cpp
1//===-- dfsan.cpp ---------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of DataFlowSanitizer.10//11// DataFlowSanitizer runtime. This file defines the public interface to12// DataFlowSanitizer as well as the definition of certain runtime functions13// called automatically by the compiler (specifically the instrumentation pass14// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp).15//16// The public interface is defined in include/sanitizer/dfsan_interface.h whose17// functions are prefixed dfsan_ while the compiler interface functions are18// prefixed __dfsan_.19//===----------------------------------------------------------------------===//20 21#include "dfsan/dfsan.h"22 23#include "dfsan/dfsan_chained_origin_depot.h"24#include "dfsan/dfsan_flags.h"25#include "dfsan/dfsan_origin.h"26#include "dfsan/dfsan_thread.h"27#include "sanitizer_common/sanitizer_atomic.h"28#include "sanitizer_common/sanitizer_common.h"29#include "sanitizer_common/sanitizer_file.h"30#include "sanitizer_common/sanitizer_flag_parser.h"31#include "sanitizer_common/sanitizer_flags.h"32#include "sanitizer_common/sanitizer_internal_defs.h"33#include "sanitizer_common/sanitizer_libc.h"34#include "sanitizer_common/sanitizer_report_decorator.h"35#include "sanitizer_common/sanitizer_stacktrace.h"36#if SANITIZER_LINUX37# include <sys/personality.h>38#endif39 40using namespace __dfsan;41 42Flags __dfsan::flags_data;43 44// The size of TLS variables. These constants must be kept in sync with the ones45// in DataFlowSanitizer.cpp.46static const int kDFsanArgTlsSize = 800;47static const int kDFsanRetvalTlsSize = 800;48static const int kDFsanArgOriginTlsSize = 800;49 50SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u6451 __dfsan_retval_tls[kDFsanRetvalTlsSize / sizeof(u64)];52SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __dfsan_retval_origin_tls;53SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u6454 __dfsan_arg_tls[kDFsanArgTlsSize / sizeof(u64)];55SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u3256 __dfsan_arg_origin_tls[kDFsanArgOriginTlsSize / sizeof(u32)];57 58// Instrumented code may set this value in terms of -dfsan-track-origins.59// * undefined or 0: do not track origins.60// * 1: track origins at memory store operations.61// * 2: track origins at memory load and store operations.62// TODO: track callsites.63extern "C" SANITIZER_WEAK_ATTRIBUTE const int __dfsan_track_origins;64 65extern "C" SANITIZER_INTERFACE_ATTRIBUTE int dfsan_get_track_origins() {66 return &__dfsan_track_origins ? __dfsan_track_origins : 0;67}68 69// On Linux/x86_64, memory is laid out as follows:70//71// +--------------------+ 0x800000000000 (top of memory)72// | application 3 |73// +--------------------+ 0x70000000000074// | invalid |75// +--------------------+ 0x61000000000076// | origin 1 |77// +--------------------+ 0x60000000000078// | application 2 |79// +--------------------+ 0x51000000000080// | shadow 1 |81// +--------------------+ 0x50000000000082// | invalid |83// +--------------------+ 0x40000000000084// | origin 3 |85// +--------------------+ 0x30000000000086// | shadow 3 |87// +--------------------+ 0x20000000000088// | origin 2 |89// +--------------------+ 0x11000000000090// | invalid |91// +--------------------+ 0x10000000000092// | shadow 2 |93// +--------------------+ 0x01000000000094// | application 1 |95// +--------------------+ 0x00000000000096//97// MEM_TO_SHADOW(mem) = mem ^ 0x50000000000098// SHADOW_TO_ORIGIN(shadow) = shadow + 0x10000000000099 100extern "C" SANITIZER_INTERFACE_ATTRIBUTE101dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) {102 dfsan_label label = ls[0];103 for (uptr i = 1; i != n; ++i)104 label |= ls[i];105 return label;106}107 108// Return the union of all the n labels from addr at the high 32 bit, and the109// origin of the first taint byte at the low 32 bit.110extern "C" SANITIZER_INTERFACE_ATTRIBUTE u64111__dfsan_load_label_and_origin(const void *addr, uptr n) {112 dfsan_label label = 0;113 u64 ret = 0;114 uptr p = (uptr)addr;115 dfsan_label *s = shadow_for((void *)p);116 for (uptr i = 0; i < n; ++i) {117 dfsan_label l = s[i];118 if (!l)119 continue;120 label |= l;121 if (!ret)122 ret = *(dfsan_origin *)origin_for((void *)(p + i));123 }124 return ret | (u64)label << 32;125}126 127extern "C" SANITIZER_INTERFACE_ATTRIBUTE128void __dfsan_unimplemented(char *fname) {129 if (flags().warn_unimplemented)130 Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n",131 fname);132}133 134extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_wrapper_extern_weak_null(135 const void *addr, char *fname) {136 if (!addr)137 Report(138 "ERROR: DataFlowSanitizer: dfsan generated wrapper calling null "139 "extern_weak function %s\nIf this only happens with dfsan, the "140 "dfsan instrumentation pass may be accidentally optimizing out a "141 "null check\n",142 fname);143}144 145// Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function146// to try to figure out where labels are being introduced in a nominally147// label-free program.148extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() {149 if (flags().warn_nonzero_labels)150 Report("WARNING: DataFlowSanitizer: saw nonzero label\n");151}152 153// Indirect call to an uninstrumented vararg function. We don't have a way of154// handling these at the moment.155extern "C" SANITIZER_INTERFACE_ATTRIBUTE void156__dfsan_vararg_wrapper(const char *fname) {157 Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg "158 "function %s\n", fname);159 Die();160}161 162// Resolves the union of two labels.163SANITIZER_INTERFACE_ATTRIBUTE dfsan_label164dfsan_union(dfsan_label l1, dfsan_label l2) {165 return l1 | l2;166}167 168static const uptr kOriginAlign = sizeof(dfsan_origin);169static const uptr kOriginAlignMask = ~(kOriginAlign - 1UL);170 171static uptr OriginAlignUp(uptr u) {172 return (u + kOriginAlign - 1) & kOriginAlignMask;173}174 175static uptr OriginAlignDown(uptr u) { return u & kOriginAlignMask; }176 177// Return the origin of the first taint byte in the size bytes from the address178// addr.179static dfsan_origin GetOriginIfTainted(uptr addr, uptr size) {180 for (uptr i = 0; i < size; ++i, ++addr) {181 dfsan_label *s = shadow_for((void *)addr);182 183 if (*s) {184 // Validate address region.185 CHECK(MEM_IS_SHADOW(s));186 return *(dfsan_origin *)origin_for((void *)addr);187 }188 }189 return 0;190}191 192// For platforms which support slow unwinder only, we need to restrict the store193// context size to 1, basically only storing the current pc, because the slow194// unwinder which is based on libunwind is not async signal safe and causes195// random freezes in forking applications as well as in signal handlers.196// DFSan supports only Linux. So we do not restrict the store context size.197#define GET_STORE_STACK_TRACE_PC_BP(pc, bp) \198 UNINITIALIZED BufferedStackTrace stack; \199 stack.Unwind(pc, bp, nullptr, true, flags().store_context_size);200 201#define PRINT_CALLER_STACK_TRACE \202 { \203 GET_CALLER_PC_BP; \204 GET_STORE_STACK_TRACE_PC_BP(pc, bp) \205 stack.Print(); \206 }207 208// Return a chain with the previous ID id and the current stack.209// from_init = true if this is the first chain of an origin tracking path.210static u32 ChainOrigin(u32 id, StackTrace *stack, bool from_init = false) {211 // StackDepot is not async signal safe. Do not create new chains in a signal212 // handler.213 DFsanThread *t = GetCurrentThread();214 if (t && t->InSignalHandler())215 return id;216 217 // As an optimization the origin of an application byte is updated only when218 // its shadow is non-zero. Because we are only interested in the origins of219 // taint labels, it does not matter what origin a zero label has. This reduces220 // memory write cost. MSan does similar optimization. The following invariant221 // may not hold because of some bugs. We check the invariant to help debug.222 if (!from_init && id == 0 && flags().check_origin_invariant) {223 Printf(" DFSan found invalid origin invariant\n");224 PRINT_CALLER_STACK_TRACE225 }226 227 Origin o = Origin::FromRawId(id);228 stack->tag = StackTrace::TAG_UNKNOWN;229 Origin chained = Origin::CreateChainedOrigin(o, stack);230 return chained.raw_id();231}232 233static void ChainAndWriteOriginIfTainted(uptr src, uptr size, uptr dst,234 StackTrace *stack) {235 dfsan_origin o = GetOriginIfTainted(src, size);236 if (o) {237 o = ChainOrigin(o, stack);238 *(dfsan_origin *)origin_for((void *)dst) = o;239 }240}241 242// Copy the origins of the size bytes from src to dst. The source and target243// memory ranges cannot be overlapped. This is used by memcpy. stack records the244// stack trace of the memcpy. When dst and src are not 4-byte aligned properly,245// origins at the unaligned address boundaries may be overwritten because four246// contiguous bytes share the same origin.247static void CopyOrigin(const void *dst, const void *src, uptr size,248 StackTrace *stack) {249 uptr d = (uptr)dst;250 uptr beg = OriginAlignDown(d);251 // Copy left unaligned origin if that memory is tainted.252 if (beg < d) {253 ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);254 beg += kOriginAlign;255 }256 257 uptr end = OriginAlignDown(d + size);258 // If both ends fall into the same 4-byte slot, we are done.259 if (end < beg)260 return;261 262 // Copy right unaligned origin if that memory is tainted.263 if (end < d + size)264 ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,265 stack);266 267 if (beg >= end)268 return;269 270 // Align src up.271 uptr src_a = OriginAlignUp((uptr)src);272 dfsan_origin *src_o = origin_for((void *)src_a);273 u32 *src_s = (u32 *)shadow_for((void *)src_a);274 dfsan_origin *src_end = origin_for((void *)(src_a + (end - beg)));275 dfsan_origin *dst_o = origin_for((void *)beg);276 dfsan_origin last_src_o = 0;277 dfsan_origin last_dst_o = 0;278 for (; src_o < src_end; ++src_o, ++src_s, ++dst_o) {279 if (!*src_s)280 continue;281 if (*src_o != last_src_o) {282 last_src_o = *src_o;283 last_dst_o = ChainOrigin(last_src_o, stack);284 }285 *dst_o = last_dst_o;286 }287}288 289// Copy the origins of the size bytes from src to dst. The source and target290// memory ranges may be overlapped. So the copy is done in a reverse order.291// This is used by memmove. stack records the stack trace of the memmove.292static void ReverseCopyOrigin(const void *dst, const void *src, uptr size,293 StackTrace *stack) {294 uptr d = (uptr)dst;295 uptr end = OriginAlignDown(d + size);296 297 // Copy right unaligned origin if that memory is tainted.298 if (end < d + size)299 ChainAndWriteOriginIfTainted((uptr)src + (end - d), (d + size) - end, end,300 stack);301 302 uptr beg = OriginAlignDown(d);303 304 if (beg + kOriginAlign < end) {305 // Align src up.306 uptr src_a = OriginAlignUp((uptr)src);307 void *src_end = (void *)(src_a + end - beg - kOriginAlign);308 dfsan_origin *src_end_o = origin_for(src_end);309 u32 *src_end_s = (u32 *)shadow_for(src_end);310 dfsan_origin *src_begin_o = origin_for((void *)src_a);311 dfsan_origin *dst = origin_for((void *)(end - kOriginAlign));312 dfsan_origin last_src_o = 0;313 dfsan_origin last_dst_o = 0;314 for (; src_end_o >= src_begin_o; --src_end_o, --src_end_s, --dst) {315 if (!*src_end_s)316 continue;317 if (*src_end_o != last_src_o) {318 last_src_o = *src_end_o;319 last_dst_o = ChainOrigin(last_src_o, stack);320 }321 *dst = last_dst_o;322 }323 }324 325 // Copy left unaligned origin if that memory is tainted.326 if (beg < d)327 ChainAndWriteOriginIfTainted((uptr)src, beg + kOriginAlign - d, beg, stack);328}329 330// Copy or move the origins of the len bytes from src to dst. The source and331// target memory ranges may or may not be overlapped. This is used by memory332// transfer operations. stack records the stack trace of the memory transfer333// operation.334static void MoveOrigin(const void *dst, const void *src, uptr size,335 StackTrace *stack) {336 // Validate address regions.337 if (!MEM_IS_SHADOW(shadow_for(dst)) ||338 !MEM_IS_SHADOW(shadow_for((void *)((uptr)dst + size))) ||339 !MEM_IS_SHADOW(shadow_for(src)) ||340 !MEM_IS_SHADOW(shadow_for((void *)((uptr)src + size)))) {341 CHECK(false);342 return;343 }344 // If destination origin range overlaps with source origin range, move345 // origins by copying origins in a reverse order; otherwise, copy origins in346 // a normal order. The orders of origin transfer are consistent with the347 // orders of how memcpy and memmove transfer user data.348 uptr src_aligned_beg = OriginAlignDown((uptr)src);349 uptr src_aligned_end = OriginAlignDown((uptr)src + size);350 uptr dst_aligned_beg = OriginAlignDown((uptr)dst);351 if (dst_aligned_beg < src_aligned_end && dst_aligned_beg >= src_aligned_beg)352 return ReverseCopyOrigin(dst, src, size, stack);353 return CopyOrigin(dst, src, size, stack);354}355 356// Set the size bytes from the addres dst to be the origin value.357static void SetOrigin(const void *dst, uptr size, u32 origin) {358 if (size == 0)359 return;360 361 // Origin mapping is 4 bytes per 4 bytes of application memory.362 // Here we extend the range such that its left and right bounds are both363 // 4 byte aligned.364 uptr x = unaligned_origin_for((uptr)dst);365 uptr beg = OriginAlignDown(x);366 uptr end = OriginAlignUp(x + size); // align up.367 u64 origin64 = ((u64)origin << 32) | origin;368 // This is like memset, but the value is 32-bit. We unroll by 2 to write369 // 64 bits at once. May want to unroll further to get 128-bit stores.370 if (beg & 7ULL) {371 if (*(u32 *)beg != origin)372 *(u32 *)beg = origin;373 beg += 4;374 }375 for (uptr addr = beg; addr < (end & ~7UL); addr += 8) {376 if (*(u64 *)addr == origin64)377 continue;378 *(u64 *)addr = origin64;379 }380 if (end & 7ULL)381 if (*(u32 *)(end - kOriginAlign) != origin)382 *(u32 *)(end - kOriginAlign) = origin;383}384 385#define RET_CHAIN_ORIGIN(id) \386 GET_CALLER_PC_BP; \387 GET_STORE_STACK_TRACE_PC_BP(pc, bp); \388 return ChainOrigin(id, &stack);389 390// Return a new origin chain with the previous ID id and the current stack391// trace.392extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin393__dfsan_chain_origin(dfsan_origin id) {394 RET_CHAIN_ORIGIN(id)395}396 397// Return a new origin chain with the previous ID id and the current stack398// trace if the label is tainted.399extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin400__dfsan_chain_origin_if_tainted(dfsan_label label, dfsan_origin id) {401 if (!label)402 return id;403 RET_CHAIN_ORIGIN(id)404}405 406// Copy or move the origins of the len bytes from src to dst.407extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_mem_origin_transfer(408 const void *dst, const void *src, uptr len) {409 if (src == dst)410 return;411 GET_CALLER_PC_BP;412 GET_STORE_STACK_TRACE_PC_BP(pc, bp);413 MoveOrigin(dst, src, len, &stack);414}415 416extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_origin_transfer(417 const void *dst, const void *src, uptr len) {418 __dfsan_mem_origin_transfer(dst, src, len);419}420 421static void CopyShadow(void *dst, const void *src, uptr len) {422 internal_memcpy((void *)__dfsan::shadow_for(dst),423 (const void *)__dfsan::shadow_for(src),424 len * sizeof(dfsan_label));425}426 427extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_mem_shadow_transfer(428 void *dst, const void *src, uptr len) {429 CopyShadow(dst, src, len);430}431 432// Copy shadow and origins of the len bytes from src to dst.433extern "C" SANITIZER_INTERFACE_ATTRIBUTE void434__dfsan_mem_shadow_origin_transfer(void *dst, const void *src, uptr size) {435 if (src == dst)436 return;437 CopyShadow(dst, src, size);438 if (dfsan_get_track_origins()) {439 // Duplicating code instead of calling __dfsan_mem_origin_transfer440 // so that the getting the caller stack frame works correctly.441 GET_CALLER_PC_BP;442 GET_STORE_STACK_TRACE_PC_BP(pc, bp);443 MoveOrigin(dst, src, size, &stack);444 }445}446 447// Copy shadow and origins as per __atomic_compare_exchange.448extern "C" SANITIZER_INTERFACE_ATTRIBUTE void449__dfsan_mem_shadow_origin_conditional_exchange(u8 condition, void *target,450 void *expected,451 const void *desired, uptr size) {452 void *dst;453 const void *src;454 // condition is result of native call to __atomic_compare_exchange455 if (condition) {456 // Copy desired into target457 dst = target;458 src = desired;459 } else {460 // Copy target into expected461 dst = expected;462 src = target;463 }464 if (src == dst)465 return;466 CopyShadow(dst, src, size);467 if (dfsan_get_track_origins()) {468 // Duplicating code instead of calling __dfsan_mem_origin_transfer469 // so that the getting the caller stack frame works correctly.470 GET_CALLER_PC_BP;471 GET_STORE_STACK_TRACE_PC_BP(pc, bp);472 MoveOrigin(dst, src, size, &stack);473 }474}475 476bool __dfsan::dfsan_inited;477bool __dfsan::dfsan_init_is_running;478 479void __dfsan::dfsan_copy_memory(void *dst, const void *src, uptr size) {480 internal_memcpy(dst, src, size);481 dfsan_mem_shadow_transfer(dst, src, size);482 if (dfsan_get_track_origins())483 dfsan_mem_origin_transfer(dst, src, size);484}485 486// Releases the pages within the origin address range.487static void ReleaseOrigins(void *addr, uptr size) {488 const uptr beg_origin_addr = (uptr)__dfsan::origin_for(addr);489 const void *end_addr = (void *)((uptr)addr + size);490 const uptr end_origin_addr = (uptr)__dfsan::origin_for(end_addr);491 492 if (end_origin_addr - beg_origin_addr <493 common_flags()->clear_shadow_mmap_threshold)494 return;495 496 const uptr page_size = GetPageSizeCached();497 const uptr beg_aligned = RoundUpTo(beg_origin_addr, page_size);498 const uptr end_aligned = RoundDownTo(end_origin_addr, page_size);499 500 if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))501 Die();502}503 504static void WriteZeroShadowInRange(uptr beg, uptr end) {505 // Don't write the label if it is already the value we need it to be.506 // In a program where most addresses are not labeled, it is common that507 // a page of shadow memory is entirely zeroed. The Linux copy-on-write508 // implementation will share all of the zeroed pages, making a copy of a509 // page when any value is written. The un-sharing will happen even if510 // the value written does not change the value in memory. Avoiding the511 // write when both |label| and |*labelp| are zero dramatically reduces512 // the amount of real memory used by large programs.513 if (!mem_is_zero((const char *)beg, end - beg))514 internal_memset((void *)beg, 0, end - beg);515}516 517// Releases the pages within the shadow address range, and sets518// the shadow addresses not on the pages to be 0.519static void ReleaseOrClearShadows(void *addr, uptr size) {520 const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);521 const void *end_addr = (void *)((uptr)addr + size);522 const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr);523 524 if (end_shadow_addr - beg_shadow_addr <525 common_flags()->clear_shadow_mmap_threshold) {526 WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);527 return;528 }529 530 const uptr page_size = GetPageSizeCached();531 const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size);532 const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size);533 534 if (beg_aligned >= end_aligned) {535 WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr);536 } else {537 if (beg_aligned != beg_shadow_addr)538 WriteZeroShadowInRange(beg_shadow_addr, beg_aligned);539 if (end_aligned != end_shadow_addr)540 WriteZeroShadowInRange(end_aligned, end_shadow_addr);541 if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned))542 Die();543 }544}545 546static void SetShadow(dfsan_label label, void *addr, uptr size,547 dfsan_origin origin) {548 if (0 != label) {549 const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr);550 internal_memset((void *)beg_shadow_addr, label, size);551 if (dfsan_get_track_origins())552 SetOrigin(addr, size, origin);553 return;554 }555 556 if (dfsan_get_track_origins())557 ReleaseOrigins(addr, size);558 559 ReleaseOrClearShadows(addr, size);560}561 562// If the label s is tainted, set the size bytes from the address p to be a new563// origin chain with the previous ID o and the current stack trace. This is564// used by instrumentation to reduce code size when too much code is inserted.565extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin(566 dfsan_label s, void *p, uptr size, dfsan_origin o) {567 if (UNLIKELY(s)) {568 GET_CALLER_PC_BP;569 GET_STORE_STACK_TRACE_PC_BP(pc, bp);570 SetOrigin(p, size, ChainOrigin(o, &stack));571 }572}573 574extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(575 dfsan_label label, dfsan_origin origin, void *addr, uptr size) {576 SetShadow(label, addr, size, origin);577}578 579SANITIZER_INTERFACE_ATTRIBUTE580void dfsan_set_label(dfsan_label label, void *addr, uptr size) {581 dfsan_origin init_origin = 0;582 if (label && dfsan_get_track_origins()) {583 GET_CALLER_PC_BP;584 GET_STORE_STACK_TRACE_PC_BP(pc, bp);585 init_origin = ChainOrigin(0, &stack, true);586 }587 SetShadow(label, addr, size, init_origin);588}589 590SANITIZER_INTERFACE_ATTRIBUTE591void dfsan_add_label(dfsan_label label, void *addr, uptr size) {592 if (0 == label)593 return;594 595 if (dfsan_get_track_origins()) {596 GET_CALLER_PC_BP;597 GET_STORE_STACK_TRACE_PC_BP(pc, bp);598 dfsan_origin init_origin = ChainOrigin(0, &stack, true);599 SetOrigin(addr, size, init_origin);600 }601 602 for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp)603 *labelp |= label;604}605 606// Unlike the other dfsan interface functions the behavior of this function607// depends on the label of one of its arguments. Hence it is implemented as a608// custom function.609extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label610__dfsw_dfsan_get_label(long data, dfsan_label data_label,611 dfsan_label *ret_label) {612 *ret_label = 0;613 return data_label;614}615 616extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfso_dfsan_get_label(617 long data, dfsan_label data_label, dfsan_label *ret_label,618 dfsan_origin data_origin, dfsan_origin *ret_origin) {619 *ret_label = 0;620 *ret_origin = 0;621 return data_label;622}623 624// This function is used if dfsan_get_origin is called when origin tracking is625// off.626extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfsw_dfsan_get_origin(627 long data, dfsan_label data_label, dfsan_label *ret_label) {628 *ret_label = 0;629 return 0;630}631 632extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfso_dfsan_get_origin(633 long data, dfsan_label data_label, dfsan_label *ret_label,634 dfsan_origin data_origin, dfsan_origin *ret_origin) {635 *ret_label = 0;636 *ret_origin = 0;637 return data_origin;638}639 640SANITIZER_INTERFACE_ATTRIBUTE dfsan_label641dfsan_read_label(const void *addr, uptr size) {642 if (size == 0)643 return 0;644 return __dfsan_union_load(shadow_for(addr), size);645}646 647SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin648dfsan_read_origin_of_first_taint(const void *addr, uptr size) {649 return GetOriginIfTainted((uptr)addr, size);650}651 652SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label_origin(dfsan_label label,653 dfsan_origin origin,654 void *addr,655 uptr size) {656 __dfsan_set_label(label, origin, addr, size);657}658 659extern "C" SANITIZER_INTERFACE_ATTRIBUTE int660dfsan_has_label(dfsan_label label, dfsan_label elem) {661 return (label & elem) == elem;662}663 664namespace __dfsan {665typedef void (*dfsan_conditional_callback_t)(dfsan_label label,666 dfsan_origin origin);667 668} // namespace __dfsan669static dfsan_conditional_callback_t conditional_callback = nullptr;670static dfsan_label labels_in_signal_conditional = 0;671 672static void ConditionalCallback(dfsan_label label, dfsan_origin origin) {673 // Programs have many branches. For efficiency the conditional sink callback674 // handler needs to ignore as many as possible as early as possible.675 if (label == 0) {676 return;677 }678 if (conditional_callback == nullptr) {679 return;680 }681 682 // This initial ConditionalCallback handler needs to be in here in dfsan683 // runtime (rather than being an entirely user implemented hook) so that it684 // has access to dfsan thread information.685 DFsanThread *t = GetCurrentThread();686 // A callback operation which does useful work (like record the flow) will687 // likely be too long executed in a signal handler.688 if (t && t->InSignalHandler()) {689 // Record set of labels used in signal handler for completeness.690 labels_in_signal_conditional |= label;691 return;692 }693 694 conditional_callback(label, origin);695}696 697extern "C" SANITIZER_INTERFACE_ATTRIBUTE void698__dfsan_conditional_callback_origin(dfsan_label label, dfsan_origin origin) {699 ConditionalCallback(label, origin);700}701 702extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_conditional_callback(703 dfsan_label label) {704 ConditionalCallback(label, 0);705}706 707extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_conditional_callback(708 __dfsan::dfsan_conditional_callback_t callback) {709 conditional_callback = callback;710}711 712extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label713dfsan_get_labels_in_signal_conditional() {714 return labels_in_signal_conditional;715}716 717namespace __dfsan {718typedef void (*dfsan_reaches_function_callback_t)(dfsan_label label,719 dfsan_origin origin,720 const char *file,721 unsigned int line,722 const char *function);723 724} // namespace __dfsan725static dfsan_reaches_function_callback_t reaches_function_callback = nullptr;726static dfsan_label labels_in_signal_reaches_function = 0;727 728static void ReachesFunctionCallback(dfsan_label label, dfsan_origin origin,729 const char *file, unsigned int line,730 const char *function) {731 if (label == 0) {732 return;733 }734 if (reaches_function_callback == nullptr) {735 return;736 }737 738 // This initial ReachesFunctionCallback handler needs to be in here in dfsan739 // runtime (rather than being an entirely user implemented hook) so that it740 // has access to dfsan thread information.741 DFsanThread *t = GetCurrentThread();742 // A callback operation which does useful work (like record the flow) will743 // likely be too long executed in a signal handler.744 if (t && t->InSignalHandler()) {745 // Record set of labels used in signal handler for completeness.746 labels_in_signal_reaches_function |= label;747 return;748 }749 750 reaches_function_callback(label, origin, file, line, function);751}752 753extern "C" SANITIZER_INTERFACE_ATTRIBUTE void754__dfsan_reaches_function_callback_origin(dfsan_label label, dfsan_origin origin,755 const char *file, unsigned int line,756 const char *function) {757 ReachesFunctionCallback(label, origin, file, line, function);758}759 760extern "C" SANITIZER_INTERFACE_ATTRIBUTE void761__dfsan_reaches_function_callback(dfsan_label label, const char *file,762 unsigned int line, const char *function) {763 ReachesFunctionCallback(label, 0, file, line, function);764}765 766extern "C" SANITIZER_INTERFACE_ATTRIBUTE void767dfsan_set_reaches_function_callback(768 __dfsan::dfsan_reaches_function_callback_t callback) {769 reaches_function_callback = callback;770}771 772extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label773dfsan_get_labels_in_signal_reaches_function() {774 return labels_in_signal_reaches_function;775}776 777namespace {778class Decorator : public __sanitizer::SanitizerCommonDecorator {779 public:780 Decorator() : SanitizerCommonDecorator() {}781 const char *Origin() const { return Magenta(); }782};783} // namespace784 785static void PrintNoOriginTrackingWarning() {786 Decorator d;787 Printf(788 " %sDFSan: origin tracking is not enabled. Did you specify the "789 "-dfsan-track-origins=1 option?%s\n",790 d.Warning(), d.Default());791}792 793static void PrintNoTaintWarning(const void *address) {794 Decorator d;795 Printf(" %sDFSan: no tainted value at %zx%s\n", d.Warning(), (uptr)address,796 d.Default());797}798 799static void PrintInvalidOriginWarning(dfsan_label label, const void *address) {800 Decorator d;801 Printf(802 " %sTaint value 0x%x (at %p) has invalid origin tracking. This can "803 "be a DFSan bug.%s\n",804 d.Warning(), label, address, d.Default());805}806 807static void PrintInvalidOriginIdWarning(dfsan_origin origin) {808 Decorator d;809 Printf(810 " %sOrigin Id %d has invalid origin tracking. This can "811 "be a DFSan bug.%s\n",812 d.Warning(), origin, d.Default());813}814 815static bool PrintOriginTraceFramesToStr(Origin o, InternalScopedString *out) {816 Decorator d;817 bool found = false;818 819 while (o.isChainedOrigin()) {820 StackTrace stack;821 dfsan_origin origin_id = o.raw_id();822 o = o.getNextChainedOrigin(&stack);823 if (o.isChainedOrigin())824 out->AppendF(825 " %sOrigin value: 0x%x, Taint value was stored to memory at%s\n",826 d.Origin(), origin_id, d.Default());827 else828 out->AppendF(" %sOrigin value: 0x%x, Taint value was created at%s\n",829 d.Origin(), origin_id, d.Default());830 831 // Includes a trailing newline, so no need to add it again.832 stack.PrintTo(out);833 found = true;834 }835 836 return found;837}838 839static bool PrintOriginTraceToStr(const void *addr, const char *description,840 InternalScopedString *out) {841 CHECK(out);842 CHECK(dfsan_get_track_origins());843 Decorator d;844 845 const dfsan_label label = *__dfsan::shadow_for(addr);846 CHECK(label);847 848 const dfsan_origin origin = *__dfsan::origin_for(addr);849 850 out->AppendF(" %sTaint value 0x%x (at %p) origin tracking (%s)%s\n",851 d.Origin(), label, addr, description ? description : "",852 d.Default());853 854 Origin o = Origin::FromRawId(origin);855 return PrintOriginTraceFramesToStr(o, out);856}857 858extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace(859 const void *addr, const char *description) {860 if (!dfsan_get_track_origins()) {861 PrintNoOriginTrackingWarning();862 return;863 }864 865 const dfsan_label label = *__dfsan::shadow_for(addr);866 if (!label) {867 PrintNoTaintWarning(addr);868 return;869 }870 871 InternalScopedString trace;872 bool success = PrintOriginTraceToStr(addr, description, &trace);873 874 if (trace.length())875 Printf("%s", trace.data());876 877 if (!success)878 PrintInvalidOriginWarning(label, addr);879}880 881extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr882dfsan_sprint_origin_trace(const void *addr, const char *description,883 char *out_buf, uptr out_buf_size) {884 CHECK(out_buf);885 886 if (!dfsan_get_track_origins()) {887 PrintNoOriginTrackingWarning();888 return 0;889 }890 891 const dfsan_label label = *__dfsan::shadow_for(addr);892 if (!label) {893 PrintNoTaintWarning(addr);894 return 0;895 }896 897 InternalScopedString trace;898 bool success = PrintOriginTraceToStr(addr, description, &trace);899 900 if (!success) {901 PrintInvalidOriginWarning(label, addr);902 return 0;903 }904 905 if (out_buf_size) {906 internal_strncpy(out_buf, trace.data(), out_buf_size - 1);907 out_buf[out_buf_size - 1] = '\0';908 }909 910 return trace.length();911}912 913extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_id_trace(914 dfsan_origin origin) {915 if (!dfsan_get_track_origins()) {916 PrintNoOriginTrackingWarning();917 return;918 }919 Origin o = Origin::FromRawId(origin);920 921 InternalScopedString trace;922 bool success = PrintOriginTraceFramesToStr(o, &trace);923 924 if (trace.length())925 Printf("%s", trace.data());926 927 if (!success)928 PrintInvalidOriginIdWarning(origin);929}930 931extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_sprint_origin_id_trace(932 dfsan_origin origin, char *out_buf, uptr out_buf_size) {933 CHECK(out_buf);934 935 if (!dfsan_get_track_origins()) {936 PrintNoOriginTrackingWarning();937 return 0;938 }939 Origin o = Origin::FromRawId(origin);940 941 InternalScopedString trace;942 bool success = PrintOriginTraceFramesToStr(o, &trace);943 944 if (!success) {945 PrintInvalidOriginIdWarning(origin);946 return 0;947 }948 949 if (out_buf_size) {950 internal_strncpy(out_buf, trace.data(), out_buf_size - 1);951 out_buf[out_buf_size - 1] = '\0';952 }953 954 return trace.length();955}956 957extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin958dfsan_get_init_origin(const void *addr) {959 if (!dfsan_get_track_origins())960 return 0;961 962 const dfsan_label label = *__dfsan::shadow_for(addr);963 if (!label)964 return 0;965 966 const dfsan_origin origin = *__dfsan::origin_for(addr);967 968 Origin o = Origin::FromRawId(origin);969 dfsan_origin origin_id = o.raw_id();970 while (o.isChainedOrigin()) {971 StackTrace stack;972 origin_id = o.raw_id();973 o = o.getNextChainedOrigin(&stack);974 }975 return origin_id;976}977 978void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,979 void *context,980 bool request_fast,981 u32 max_depth) {982 using namespace __dfsan;983 DFsanThread *t = GetCurrentThread();984 if (!t || !StackTrace::WillUseFastUnwind(request_fast)) {985 return Unwind(max_depth, pc, bp, context, 0, 0, false);986 }987 Unwind(max_depth, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), true);988}989 990extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() {991 GET_CALLER_PC_BP;992 GET_STORE_STACK_TRACE_PC_BP(pc, bp);993 stack.Print();994}995 996extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr997dfsan_sprint_stack_trace(char *out_buf, uptr out_buf_size) {998 CHECK(out_buf);999 GET_CALLER_PC_BP;1000 GET_STORE_STACK_TRACE_PC_BP(pc, bp);1001 return stack.PrintTo(out_buf, out_buf_size);1002}1003 1004void Flags::SetDefaults() {1005#define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;1006#include "dfsan_flags.inc"1007#undef DFSAN_FLAG1008}1009 1010static void RegisterDfsanFlags(FlagParser *parser, Flags *f) {1011#define DFSAN_FLAG(Type, Name, DefaultValue, Description) \1012 RegisterFlag(parser, #Name, Description, &f->Name);1013#include "dfsan_flags.inc"1014#undef DFSAN_FLAG1015}1016 1017static void InitializeFlags() {1018 SetCommonFlagsDefaults();1019 {1020 CommonFlags cf;1021 cf.CopyFrom(*common_flags());1022 cf.intercept_tls_get_addr = true;1023 OverrideCommonFlags(cf);1024 }1025 flags().SetDefaults();1026 1027 FlagParser parser;1028 RegisterCommonFlags(&parser);1029 RegisterDfsanFlags(&parser, &flags());1030 parser.ParseStringFromEnv("DFSAN_OPTIONS");1031 InitializeCommonFlags();1032 if (Verbosity()) ReportUnrecognizedFlags();1033 if (common_flags()->help) parser.PrintFlagDescriptions();1034}1035 1036SANITIZER_INTERFACE_ATTRIBUTE1037void dfsan_clear_arg_tls(uptr offset, uptr size) {1038 internal_memset((void *)((uptr)__dfsan_arg_tls + offset), 0, size);1039}1040 1041SANITIZER_INTERFACE_ATTRIBUTE1042void dfsan_clear_thread_local_state() {1043 internal_memset(__dfsan_arg_tls, 0, sizeof(__dfsan_arg_tls));1044 internal_memset(__dfsan_retval_tls, 0, sizeof(__dfsan_retval_tls));1045 1046 if (dfsan_get_track_origins()) {1047 internal_memset(__dfsan_arg_origin_tls, 0, sizeof(__dfsan_arg_origin_tls));1048 internal_memset(&__dfsan_retval_origin_tls, 0,1049 sizeof(__dfsan_retval_origin_tls));1050 }1051}1052 1053SANITIZER_INTERFACE_ATTRIBUTE1054void dfsan_set_arg_tls(uptr offset, dfsan_label label) {1055 // 2x to match ShadowTLSAlignment.1056 // ShadowTLSAlignment should probably be changed.1057 // TODO: Consider reducing ShadowTLSAlignment to 1.1058 // Aligning to 2 bytes is probably a remnant of fast16 mode.1059 ((dfsan_label *)__dfsan_arg_tls)[offset * 2] = label;1060}1061 1062SANITIZER_INTERFACE_ATTRIBUTE1063void dfsan_set_arg_origin_tls(uptr offset, dfsan_origin o) {1064 __dfsan_arg_origin_tls[offset] = o;1065}1066 1067extern "C" void dfsan_flush() {1068 const uptr maxVirtualAddress = GetMaxUserVirtualAddress();1069 for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {1070 uptr start = kMemoryLayout[i].start;1071 uptr end = kMemoryLayout[i].end;1072 uptr size = end - start;1073 MappingDesc::Type type = kMemoryLayout[i].type;1074 1075 if (type != MappingDesc::SHADOW && type != MappingDesc::ORIGIN)1076 continue;1077 1078 // Check if the segment should be mapped based on platform constraints.1079 if (start >= maxVirtualAddress)1080 continue;1081 1082 if (!MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name)) {1083 Printf("FATAL: DataFlowSanitizer: failed to clear memory region\n");1084 Die();1085 }1086 }1087 labels_in_signal_conditional = 0;1088 labels_in_signal_reaches_function = 0;1089}1090 1091// TODO: CheckMemoryLayoutSanity is based on msan.1092// Consider refactoring these into a shared implementation.1093static void CheckMemoryLayoutSanity() {1094 uptr prev_end = 0;1095 for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {1096 uptr start = kMemoryLayout[i].start;1097 uptr end = kMemoryLayout[i].end;1098 MappingDesc::Type type = kMemoryLayout[i].type;1099 CHECK_LT(start, end);1100 CHECK_EQ(prev_end, start);1101 CHECK(addr_is_type(start, type));1102 CHECK(addr_is_type((start + end) / 2, type));1103 CHECK(addr_is_type(end - 1, type));1104 if (type == MappingDesc::APP) {1105 uptr addr = start;1106 CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));1107 CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));1108 CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));1109 1110 addr = (start + end) / 2;1111 CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));1112 CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));1113 CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));1114 1115 addr = end - 1;1116 CHECK(MEM_IS_SHADOW(MEM_TO_SHADOW(addr)));1117 CHECK(MEM_IS_ORIGIN(MEM_TO_ORIGIN(addr)));1118 CHECK_EQ(MEM_TO_ORIGIN(addr), SHADOW_TO_ORIGIN(MEM_TO_SHADOW(addr)));1119 }1120 prev_end = end;1121 }1122}1123 1124// TODO: CheckMemoryRangeAvailability is based on msan.1125// Consider refactoring these into a shared implementation.1126static bool CheckMemoryRangeAvailability(uptr beg, uptr size, bool verbose) {1127 if (size > 0) {1128 uptr end = beg + size - 1;1129 if (!MemoryRangeIsAvailable(beg, end)) {1130 if (verbose)1131 Printf("FATAL: Memory range %p - %p is not available.\n", (void*)beg,1132 (void*)end);1133 return false;1134 }1135 }1136 return true;1137}1138 1139// TODO: ProtectMemoryRange is based on msan.1140// Consider refactoring these into a shared implementation.1141static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) {1142 if (size > 0) {1143 void *addr = MmapFixedNoAccess(beg, size, name);1144 if (beg == 0 && addr) {1145 // Depending on the kernel configuration, we may not be able to protect1146 // the page at address zero.1147 uptr gap = 16 * GetPageSizeCached();1148 beg += gap;1149 size -= gap;1150 addr = MmapFixedNoAccess(beg, size, name);1151 }1152 if ((uptr)addr != beg) {1153 uptr end = beg + size - 1;1154 Printf("FATAL: Cannot protect memory range %p - %p (%s).\n", (void*)beg,1155 (void*)end, name);1156 return false;1157 }1158 }1159 return true;1160}1161 1162// TODO: InitShadow is based on msan.1163// Consider refactoring these into a shared implementation.1164static bool InitShadow(bool init_origins, bool dry_run) {1165 // Let user know mapping parameters first.1166 VPrintf(1, "dfsan_init %p\n", (void *)&__dfsan::dfsan_init);1167 for (unsigned i = 0; i < kMemoryLayoutSize; ++i)1168 VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start,1169 kMemoryLayout[i].end - 1);1170 1171 CheckMemoryLayoutSanity();1172 1173 if (!MEM_IS_APP(&__dfsan::dfsan_init)) {1174 if (!dry_run)1175 Printf("FATAL: Code %p is out of application range. Non-PIE build?\n",1176 (void*)&__dfsan::dfsan_init);1177 return false;1178 }1179 1180 const uptr maxVirtualAddress = GetMaxUserVirtualAddress();1181 1182 for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {1183 uptr start = kMemoryLayout[i].start;1184 uptr end = kMemoryLayout[i].end;1185 uptr size = end - start;1186 MappingDesc::Type type = kMemoryLayout[i].type;1187 1188 // Check if the segment should be mapped based on platform constraints.1189 if (start >= maxVirtualAddress)1190 continue;1191 1192 bool map = type == MappingDesc::SHADOW ||1193 (init_origins && type == MappingDesc::ORIGIN);1194 bool protect = type == MappingDesc::INVALID ||1195 (!init_origins && type == MappingDesc::ORIGIN);1196 CHECK(!(map && protect));1197 if (!map && !protect) {1198 CHECK(type == MappingDesc::APP || type == MappingDesc::ALLOCATOR);1199 1200 if (dry_run && type == MappingDesc::ALLOCATOR &&1201 !CheckMemoryRangeAvailability(start, size, !dry_run))1202 return false;1203 }1204 if (map) {1205 if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))1206 return false;1207 if (!dry_run &&1208 !MmapFixedSuperNoReserve(start, size, kMemoryLayout[i].name))1209 return false;1210 if (!dry_run && common_flags()->use_madv_dontdump)1211 DontDumpShadowMemory(start, size);1212 }1213 if (protect) {1214 if (dry_run && !CheckMemoryRangeAvailability(start, size, !dry_run))1215 return false;1216 if (!dry_run && !ProtectMemoryRange(start, size, kMemoryLayout[i].name))1217 return false;1218 }1219 }1220 1221 return true;1222}1223 1224static bool InitShadowWithReExec(bool init_origins) {1225 // Start with dry run: check layout is ok, but don't print warnings because1226 // warning messages will cause tests to fail (even if we successfully re-exec1227 // after the warning).1228 bool success = InitShadow(init_origins, true);1229 if (!success) {1230#if SANITIZER_LINUX1231 // Perhaps ASLR entropy is too high. If ASLR is enabled, re-exec without it.1232 int old_personality = personality(0xffffffff);1233 bool aslr_on =1234 (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);1235 1236 if (aslr_on) {1237 VReport(1,1238 "WARNING: DataflowSanitizer: memory layout is incompatible, "1239 "possibly due to high-entropy ASLR.\n"1240 "Re-execing with fixed virtual address space.\n"1241 "N.B. reducing ASLR entropy is preferable.\n");1242 CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);1243 ReExec();1244 }1245#endif1246 }1247 1248 // The earlier dry run didn't actually map or protect anything. Run again in1249 // non-dry run mode.1250 return success && InitShadow(init_origins, false);1251}1252 1253static void DFsanInit(int argc, char **argv, char **envp) {1254 CHECK(!dfsan_init_is_running);1255 if (dfsan_inited)1256 return;1257 dfsan_init_is_running = true;1258 SanitizerToolName = "DataflowSanitizer";1259 1260 AvoidCVE_2016_2143();1261 1262 InitializeFlags();1263 1264 CheckASLR();1265 1266 InitializePlatformEarly();1267 1268 if (!InitShadowWithReExec(dfsan_get_track_origins())) {1269 Printf("FATAL: DataflowSanitizer can not mmap the shadow memory.\n");1270 DumpProcessMap();1271 Die();1272 }1273 1274 initialize_interceptors();1275 1276 // Set up threads1277 DFsanTSDInit(DFsanTSDDtor);1278 1279 dfsan_allocator_init();1280 1281 DFsanThread *main_thread = DFsanThread::Create(nullptr, nullptr);1282 SetCurrentThread(main_thread);1283 main_thread->Init();1284 1285 dfsan_init_is_running = false;1286 dfsan_inited = true;1287}1288 1289void __dfsan::dfsan_init() { DFsanInit(0, nullptr, nullptr); }1290 1291#if SANITIZER_CAN_USE_PREINIT_ARRAY1292__attribute__((section(".preinit_array"),1293 used)) static void (*dfsan_init_ptr)(int, char **,1294 char **) = DFsanInit;1295#endif1296