diff options
Diffstat (limited to 'lib/dfsan')
-rw-r--r-- | lib/dfsan/.clang-format | 1 | ||||
-rw-r--r-- | lib/dfsan/CMakeLists.txt | 17 | ||||
-rw-r--r-- | lib/dfsan/dfsan.cc | 97 | ||||
-rw-r--r-- | lib/dfsan/dfsan.h | 7 | ||||
-rw-r--r-- | lib/dfsan/dfsan_custom.cc | 48 | ||||
-rw-r--r-- | lib/dfsan/dfsan_platform.h | 107 | ||||
-rw-r--r-- | lib/dfsan/done_abilist.txt | 35 |
7 files changed, 258 insertions, 54 deletions
diff --git a/lib/dfsan/.clang-format b/lib/dfsan/.clang-format new file mode 100644 index 000000000000..f6cb8ad931f5 --- /dev/null +++ b/lib/dfsan/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Google diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt index 24ea876f210d..19a7909d0429 100644 --- a/lib/dfsan/CMakeLists.txt +++ b/lib/dfsan/CMakeLists.txt @@ -15,20 +15,19 @@ add_custom_target(dfsan) foreach(arch ${DFSAN_SUPPORTED_ARCH}) set(DFSAN_CFLAGS ${DFSAN_COMMON_CFLAGS}) append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DFSAN_CFLAGS) - add_compiler_rt_runtime(clang_rt.dfsan-${arch} ${arch} STATIC + add_compiler_rt_runtime(clang_rt.dfsan + STATIC + ARCHS ${arch} SOURCES ${DFSAN_RTL_SOURCES} $<TARGET_OBJECTS:RTInterception.${arch}> $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> - CFLAGS ${DFSAN_CFLAGS}) - set(DFSAN_NOLIBC_CFLAGS ${DFSAN_COMMON_CFLAGS} -DDFSAN_NOLIBC) - add_compiler_rt_runtime(clang_rt.dfsan-libc-${arch} ${arch} STATIC - SOURCES ${DFSAN_RTL_SOURCES} - $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - CFLAGS ${DFSAN_NOLIBC_CFLAGS}) - add_sanitizer_rt_symbols(clang_rt.dfsan-${arch} dfsan.syms.extra) + CFLAGS ${DFSAN_CFLAGS} + PARENT_TARGET dfsan) + add_sanitizer_rt_symbols(clang_rt.dfsan + ARCHS ${arch} + EXTRA dfsan.syms.extra) add_dependencies(dfsan - clang_rt.dfsan-${arch} clang_rt.dfsan-${arch}-symbols) endforeach() diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index d2e137e129c1..7285f202d060 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -42,6 +42,8 @@ Flags __dfsan::flags_data; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; +SANITIZER_INTERFACE_ATTRIBUTE uptr __dfsan_shadow_ptr_mask; + // On Linux/x86_64, memory is laid out as follows: // // +--------------------+ 0x800000000000 (top of memory) @@ -80,24 +82,52 @@ SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; // | reserved by kernel | // +--------------------+ 0x0000000000 +// On Linux/AArch64 (39-bit VMA), memory is laid out as follow: +// +// +--------------------+ 0x8000000000 (top of memory) +// | application memory | +// +--------------------+ 0x7000008000 (kAppAddr) +// | | +// | unused | +// | | +// +--------------------+ 0x1200000000 (kUnusedAddr) +// | union table | +// +--------------------+ 0x1000000000 (kUnionTableAddr) +// | shadow memory | +// +--------------------+ 0x0000010000 (kShadowAddr) +// | reserved by kernel | +// +--------------------+ 0x0000000000 + +// On Linux/AArch64 (42-bit VMA), memory is laid out as follow: +// +// +--------------------+ 0x40000000000 (top of memory) +// | application memory | +// +--------------------+ 0x3ff00008000 (kAppAddr) +// | | +// | unused | +// | | +// +--------------------+ 0x1200000000 (kUnusedAddr) +// | union table | +// +--------------------+ 0x8000000000 (kUnionTableAddr) +// | shadow memory | +// +--------------------+ 0x0000010000 (kShadowAddr) +// | reserved by kernel | +// +--------------------+ 0x0000000000 + typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels]; -#if defined(__x86_64__) -static const uptr kShadowAddr = 0x10000; -static const uptr kUnionTableAddr = 0x200000000000; -static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t); -static const uptr kAppAddr = 0x700000008000; -#elif defined(__mips64) -static const uptr kShadowAddr = 0x10000; -static const uptr kUnionTableAddr = 0x2000000000; -static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t); -static const uptr kAppAddr = 0xF000008000; -#else -# error "DFSan not supported for this platform!" +#ifdef DFSAN_RUNTIME_VMA +// Runtime detected VMA size. +int __dfsan::vmaSize; #endif +static uptr UnusedAddr() { + return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>() + + sizeof(dfsan_union_table_t); +} + static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) { - return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2]; + return &(*(dfsan_union_table_t *) UnionTableAddr())[l1][l2]; } // Checks we do not run out of labels. @@ -325,10 +355,30 @@ static void RegisterDfsanFlags(FlagParser *parser, Flags *f) { } static void InitializeFlags() { + SetCommonFlagsDefaults(); + flags().SetDefaults(); + FlagParser parser; + RegisterCommonFlags(&parser); RegisterDfsanFlags(&parser, &flags()); - flags().SetDefaults(); parser.ParseString(GetEnv("DFSAN_OPTIONS")); + SetVerbosity(common_flags()->verbosity); + if (Verbosity()) ReportUnrecognizedFlags(); + if (common_flags()->help) parser.PrintFlagDescriptions(); +} + +static void InitializePlatformEarly() { +#ifdef DFSAN_RUNTIME_VMA + __dfsan::vmaSize = + (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); + if (__dfsan::vmaSize == 39 || __dfsan::vmaSize == 42) { + __dfsan_shadow_ptr_mask = ShadowMask(); + } else { + Printf("FATAL: DataFlowSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %d - Supported 39 and 42\n", __dfsan::vmaSize); + Die(); + } +#endif } static void dfsan_fini() { @@ -347,12 +397,12 @@ static void dfsan_fini() { } } -#ifdef DFSAN_NOLIBC -extern "C" void dfsan_init() { -#else static void dfsan_init(int argc, char **argv, char **envp) { -#endif - MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr); + InitializeFlags(); + + InitializePlatformEarly(); + + MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()); // Protect the region of memory we don't use, to preserve the one-to-one // mapping from application to shadow memory. But if ASLR is disabled, Linux @@ -360,21 +410,20 @@ static void dfsan_init(int argc, char **argv, char **envp) { // works so long as the program doesn't use too much memory. We support this // case by disabling memory protection when ASLR is disabled. uptr init_addr = (uptr)&dfsan_init; - if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr)) - MmapNoAccess(kUnusedAddr, kAppAddr - kUnusedAddr); + if (!(init_addr >= UnusedAddr() && init_addr < AppAddr())) + MmapNoAccess(UnusedAddr(), AppAddr() - UnusedAddr()); - InitializeFlags(); InitializeInterceptors(); // Register the fini callback to run when the program terminates successfully // or it is killed by the runtime. Atexit(dfsan_fini); - SetDieCallback(dfsan_fini); + AddDieCallback(dfsan_fini); __dfsan_label_info[kInitializingLabel].desc = "<init label>"; } -#if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY +#if SANITIZER_CAN_USE_PREINIT_ARRAY __attribute__((section(".preinit_array"), used)) static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init; #endif diff --git a/lib/dfsan/dfsan.h b/lib/dfsan/dfsan.h index ceba3533a233..81f949e3019e 100644 --- a/lib/dfsan/dfsan.h +++ b/lib/dfsan/dfsan.h @@ -16,6 +16,7 @@ #define DFSAN_H #include "sanitizer_common/sanitizer_internal_defs.h" +#include "dfsan_platform.h" // Copy declarations from public sanitizer/dfsan_interface.h header here. typedef u16 dfsan_label; @@ -44,11 +45,7 @@ namespace __dfsan { void InitializeInterceptors(); inline dfsan_label *shadow_for(void *ptr) { -#if defined(__x86_64__) - return (dfsan_label *) ((((uptr) ptr) & ~0x700000000000) << 1); -#elif defined(__mips64) - return (dfsan_label *) ((((uptr) ptr) & ~0xF000000000) << 1); -#endif + return (dfsan_label *) ((((uptr) ptr) & ShadowMask()) << 1); } inline const dfsan_label *shadow_for(const void *ptr) { diff --git a/lib/dfsan/dfsan_custom.cc b/lib/dfsan/dfsan_custom.cc index c58b471db53c..e0cd16ab695c 100644 --- a/lib/dfsan/dfsan_custom.cc +++ b/lib/dfsan/dfsan_custom.cc @@ -43,6 +43,14 @@ using namespace __dfsan; +#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \ + do { \ + if (f) \ + f(__VA_ARGS__); \ + } while (false) +#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \ +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__); + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label, @@ -77,25 +85,23 @@ SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c, *ret_label = dfsan_union(dfsan_read_label(s, i + 1), dfsan_union(s_label, c_label)); } - return s[i] == 0 ? 0 : const_cast<char *>(s+i); + return s[i] == 0 ? nullptr : const_cast<char *>(s+i); } } } -SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE -void -dfsan_weak_hook_memcmp(uptr caller_pc, const void *s1, const void *s2, size_t n, - dfsan_label s1_label, dfsan_label s2_label, - dfsan_label n_label); +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc, + const void *s1, const void *s2, size_t n, + dfsan_label s1_label, dfsan_label s2_label, + dfsan_label n_label) SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) { - if (dfsan_weak_hook_memcmp) - dfsan_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, s1_label, s2_label, - n_label); + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n, + s1_label, s2_label, n_label); const char *cs1 = (const char *) s1, *cs2 = (const char *) s2; for (size_t i = 0; i != n; ++i) { if (cs1[i] != cs2[i]) { @@ -118,10 +124,16 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2, return 0; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc, + const char *s1, const char *s2, + dfsan_label s1_label, dfsan_label s2_label) + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2, dfsan_label s1_label, dfsan_label s2_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2, + s1_label, s2_label); for (size_t i = 0;; ++i) { if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) { if (flags().strict_data_dependencies) { @@ -153,6 +165,11 @@ __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label, return 0; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc, + const char *s1, const char *s2, size_t n, + dfsan_label s1_label, dfsan_label s2_label, + dfsan_label n_label) + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, @@ -163,6 +180,9 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2, return 0; } + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2, + n, s1_label, s2_label, n_label); + for (size_t i = 0;; ++i) { if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) { if (flags().strict_data_dependencies) { @@ -828,8 +848,8 @@ typedef void (*write_trampoline_t)( // Calls to dfsan_set_write_callback() set the values in this struct. // Calls to the custom version of write() read (and invoke) them. static struct { - write_trampoline_t write_callback_trampoline = NULL; - void *write_callback = NULL; + write_trampoline_t write_callback_trampoline = nullptr; + void *write_callback = nullptr; } write_callback_info; SANITIZER_INTERFACE_ATTRIBUTE void @@ -846,7 +866,7 @@ SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_write(int fd, const void *buf, size_t count, dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label, dfsan_label *ret_label) { - if (write_callback_info.write_callback != NULL) { + if (write_callback_info.write_callback) { write_callback_info.write_callback_trampoline( write_callback_info.write_callback, fd, buf, count, @@ -856,7 +876,7 @@ __dfsw_write(int fd, const void *buf, size_t count, *ret_label = 0; return write(fd, buf, count); } -} +} // namespace __dfsan // Type used to extract a dfsan_label with va_arg() typedef int dfsan_label_va; @@ -1112,4 +1132,4 @@ int __dfsw_snprintf(char *str, size_t size, const char *format, va_end(ap); return ret; } -} +} // extern "C" diff --git a/lib/dfsan/dfsan_platform.h b/lib/dfsan/dfsan_platform.h new file mode 100644 index 000000000000..f1d9f108e908 --- /dev/null +++ b/lib/dfsan/dfsan_platform.h @@ -0,0 +1,107 @@ +//===-- dfsan_platform.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of DataFlowSanitizer. +// +// Platform specific information for DFSan. +//===----------------------------------------------------------------------===// + +#ifndef DFSAN_PLATFORM_H +#define DFSAN_PLATFORM_H + +namespace __dfsan { + +#if defined(__x86_64__) +struct Mapping { + static const uptr kShadowAddr = 0x10000; + static const uptr kUnionTableAddr = 0x200000000000; + static const uptr kAppAddr = 0x700000008000; + static const uptr kShadowMask = ~0x700000000000; +}; +#elif defined(__mips64) +struct Mapping { + static const uptr kShadowAddr = 0x10000; + static const uptr kUnionTableAddr = 0x2000000000; + static const uptr kAppAddr = 0xF000008000; + static const uptr kShadowMask = ~0xF000000000; +}; +#elif defined(__aarch64__) +struct Mapping39 { + static const uptr kShadowAddr = 0x10000; + static const uptr kUnionTableAddr = 0x1000000000; + static const uptr kAppAddr = 0x7000008000; + static const uptr kShadowMask = ~0x7800000000; +}; + +struct Mapping42 { + static const uptr kShadowAddr = 0x10000; + static const uptr kUnionTableAddr = 0x8000000000; + static const uptr kAppAddr = 0x3ff00008000; + static const uptr kShadowMask = ~0x3c000000000; +}; + +extern int vmaSize; +# define DFSAN_RUNTIME_VMA 1 +#else +# error "DFSan not supported for this platform!" +#endif + +enum MappingType { + MAPPING_SHADOW_ADDR, + MAPPING_UNION_TABLE_ADDR, + MAPPING_APP_ADDR, + MAPPING_SHADOW_MASK +}; + +template<typename Mapping, int Type> +uptr MappingImpl(void) { + switch (Type) { + case MAPPING_SHADOW_ADDR: return Mapping::kShadowAddr; + case MAPPING_UNION_TABLE_ADDR: return Mapping::kUnionTableAddr; + case MAPPING_APP_ADDR: return Mapping::kAppAddr; + case MAPPING_SHADOW_MASK: return Mapping::kShadowMask; + } +} + +template<int Type> +uptr MappingArchImpl(void) { +#ifdef __aarch64__ + if (vmaSize == 39) + return MappingImpl<Mapping39, Type>(); + else + return MappingImpl<Mapping42, Type>(); + DCHECK(0); +#else + return MappingImpl<Mapping, Type>(); +#endif +} + +ALWAYS_INLINE +uptr ShadowAddr() { + return MappingArchImpl<MAPPING_SHADOW_ADDR>(); +} + +ALWAYS_INLINE +uptr UnionTableAddr() { + return MappingArchImpl<MAPPING_UNION_TABLE_ADDR>(); +} + +ALWAYS_INLINE +uptr AppAddr() { + return MappingArchImpl<MAPPING_APP_ADDR>(); +} + +ALWAYS_INLINE +uptr ShadowMask() { + return MappingArchImpl<MAPPING_SHADOW_MASK>(); +} + +} // namespace __dfsan + +#endif diff --git a/lib/dfsan/done_abilist.txt b/lib/dfsan/done_abilist.txt index e6c077ff1208..7ca8aeba32fe 100644 --- a/lib/dfsan/done_abilist.txt +++ b/lib/dfsan/done_abilist.txt @@ -266,10 +266,41 @@ fun:reflect.makeFuncStub=discard # Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp fun:__sanitizer_cov_trace_cmp=custom fun:__sanitizer_cov_trace_cmp=uninstrumented +# Similar for __sanitizer_cov_trace_switch +fun:__sanitizer_cov_trace_switch=custom +fun:__sanitizer_cov_trace_switch=uninstrumented # Ignores all other __sanitizer callbacks. -fun:__sanitizer_*=uninstrumented -fun:__sanitizer_*=discard +fun:__sanitizer_cov=uninstrumented +fun:__sanitizer_cov=discard +fun:__sanitizer_cov_module_init=uninstrumented +fun:__sanitizer_cov_module_init=discard +fun:__sanitizer_cov_with_check=uninstrumented +fun:__sanitizer_cov_with_check=discard +fun:__sanitizer_cov_indir_call16=uninstrumented +fun:__sanitizer_cov_indir_call16=discard +fun:__sanitizer_cov_indir_call16=uninstrumented +fun:__sanitizer_cov_indir_call16=discard +fun:__sanitizer_reset_coverage=uninstrumented +fun:__sanitizer_reset_coverage=discard +fun:__sanitizer_set_death_callback=uninstrumented +fun:__sanitizer_set_death_callback=discard +fun:__sanitizer_get_coverage_guards=uninstrumented +fun:__sanitizer_get_coverage_guards=discard +fun:__sanitizer_get_number_of_counters=uninstrumented +fun:__sanitizer_get_number_of_counters=discard +fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented +fun:__sanitizer_update_counter_bitset_and_clear_counters=discard +fun:__sanitizer_get_total_unique_coverage=uninstrumented +fun:__sanitizer_get_total_unique_coverage=discard +fun:__sanitizer_get_total_unique_coverage=uninstrumented +fun:__sanitizer_get_total_unique_coverage=discard +fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented +fun:__sanitizer_update_counter_bitset_and_clear_counters=discard + +# Ignores the dfsan wrappers. +fun:__dfsw_*=uninstrumented +fun:__dfsw_*=discard # Don't add extra parameters to the Fuzzer callback. fun:LLVMFuzzerTestOneInput=uninstrumented |