Index: include/sanitizer/dfsan_interface.h =================================================================== --- include/sanitizer/dfsan_interface.h +++ include/sanitizer/dfsan_interface.h @@ -52,6 +52,13 @@ /// Sets the label for each address in [addr,addr+size) to \c label. void dfsan_set_label(dfsan_label label, void *addr, size_t size); +// Reset labels and shadow memory for dfsan to restart from clean. +// This is intended to work in a single threaded setting (main use +// case is to avoid running out of labels in fuzzing). +// This function is not safe to use in multithreaded code or when +// there are active stack frames processing non-zero labels. +void dfsan_reset(void); + /// Sets the label for each address in [addr,addr+size) to the union of the /// current label for that address and \c label. void dfsan_add_label(dfsan_label label, void *addr, size_t size); @@ -100,9 +107,32 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label); +void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2, + dfsan_label s1_label, dfsan_label s2_label); void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label); +void dfsan_weak_hook_strchr( void *caller_pc, const char *s, + int c, dfsan_label s_label, + dfsan_label c_label); +void dfsan_weak_hook_strncasecmp(void *caller_pc, const char *s1, + const char *s2, size_t n, dfsan_label s1_label, + dfsan_label s2_label, dfsan_label n_label); +void dfsan_weak_hook_strcasecmp(void *caller_pc, const char *s1, const char *s2, + dfsan_label s1_label, dfsan_label s2_label); +void dfsan_weak_hook_strlen(void *caller_pc, const char *s, dfsan_label s_label); +void dfsan_weak_hook_memcpy(void *caller_pc, void *dest, const void *src, size_t n, + dfsan_label dest_label, dfsan_label src_label, + dfsan_label n_label); +void dfsan_weak_hook_memset(void *caller_pc, void *s, int c, size_t n, + dfsan_label s_label, dfsan_label c_label, + dfsan_label n_label); +void dfsan_weak_hook_strncpy(void *caller_pc, char *s1, const char *s2, size_t n, + dfsan_label s1_label, dfsan_label s2_label, + dfsan_label n_label); +void dfsan_weak_hook_strcpy(void *caller_pc, char *dest, const char *src, + dfsan_label dst_label, dfsan_label src_label); + #ifdef __cplusplus } // extern "C" Index: lib/dfsan/dfsan.h =================================================================== --- lib/dfsan/dfsan.h +++ lib/dfsan/dfsan.h @@ -34,6 +34,7 @@ extern "C" { void dfsan_add_label(dfsan_label label, void *addr, uptr size); void dfsan_set_label(dfsan_label label, void *addr, uptr size); +void dfsan_reset(void); dfsan_label dfsan_read_label(const void *addr, uptr size); dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2); } // extern "C" Index: lib/dfsan/dfsan.cc =================================================================== --- lib/dfsan/dfsan.cc +++ lib/dfsan/dfsan.cc @@ -26,6 +26,7 @@ #include "sanitizer_common/sanitizer_libc.h" #include "dfsan/dfsan.h" +#include using namespace __dfsan; @@ -158,6 +159,20 @@ } } +// Reset labels and shadow memory for dfsan to restart from clean. +// This is intended to work in a single threaded setting (to avoid +// running out of labels in fuzzing). +// This function is not safe to use in multithreaded code or when +// there are active stack frames processing non-zero labels. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void dfsan_reset(void) { + // reset label count + atomic_store(&__dfsan_last_label, 0, memory_order_relaxed); + // reset shadow memory + MmapFixedNoReserve(ShadowAddr(), UnusedAddr() - ShadowAddr()); + assert(atomic_load(&__dfsan_last_label, memory_order_relaxed) == 0); +} + // Resolves the union of two unequal labels. Nonequality is a precondition for // this function (the instrumentation pass inlines the equality test). extern "C" SANITIZER_INTERFACE_ATTRIBUTE Index: lib/dfsan/dfsan_custom.cc =================================================================== --- lib/dfsan/dfsan_custom.cc +++ lib/dfsan/dfsan_custom.cc @@ -43,7 +43,7 @@ using namespace __dfsan; -#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \ +#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \ do { \ if (f) \ f(__VA_ARGS__); \ @@ -73,10 +73,17 @@ return ret; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strchr, uptr caller_pc, + const char *s, int c, dfsan_label s_label, + dfsan_label c_label) + SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c, dfsan_label s_label, dfsan_label c_label, dfsan_label *ret_label) { + + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strchr, GET_CALLER_PC(), s, c, + s_label, c_label); for (size_t i = 0;; ++i) { if (s[i] == c || s[i] == 0) { if (flags().strict_data_dependencies) { @@ -148,9 +155,15 @@ return 0; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcasecmp, uptr caller_pc, + const char *s1, const char *s2, + dfsan_label s1_label, dfsan_label s2_label) + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcasecmp(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_strcasecmp, GET_CALLER_PC(), + s1, s2, s1_label, s2_label); for (size_t i = 0;; ++i) { if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) { if (flags().strict_data_dependencies) { @@ -197,10 +210,18 @@ return 0; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncasecmp, 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_strncasecmp(const char *s1, const char *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncasecmp, GET_CALLER_PC(), + s1, s2, n, s1_label, s2_label, n_label); + if (n == 0) { *ret_label = 0; return 0; @@ -231,8 +252,13 @@ return p; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strlen, uptr caller_pc, + const char *s, dfsan_label s_label) + SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strlen, GET_CALLER_PC(), + s, s_label); size_t ret = strlen(s); if (flags().strict_data_dependencies) { *ret_label = 0; @@ -242,7 +268,6 @@ return ret; } - static void *dfsan_memcpy(void *dest, const void *src, size_t n) { dfsan_label *sdest = shadow_for(dest); const dfsan_label *ssrc = shadow_for(src); @@ -255,25 +280,43 @@ dfsan_set_label(c_label, s, n); } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcpy, uptr caller_pc, + void *dest, const void *src, size_t n, + dfsan_label dest_label, dfsan_label src_label, + dfsan_label n_label) + SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memcpy(void *dest, const void *src, size_t n, dfsan_label dest_label, dfsan_label src_label, dfsan_label n_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcpy, GET_CALLER_PC(), dest, src, + n, dest_label, src_label, n_label); *ret_label = dest_label; return dfsan_memcpy(dest, src, n); } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memset, uptr caller_pc, + void *s, int c, size_t n, + dfsan_label s_label, dfsan_label c_label, + dfsan_label n_label) + SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memset(void *s, int c, size_t n, dfsan_label s_label, dfsan_label c_label, dfsan_label n_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memset, GET_CALLER_PC(), + s, c, n, s_label, c_label, n_label); dfsan_memset(s, c, c_label, n); *ret_label = s_label; return s; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strdup, uptr caller_pc, + const char *s, dfsan_label s_label) + SANITIZER_INTERFACE_ATTRIBUTE char * __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strdup, GET_CALLER_PC(), s, s_label); size_t len = strlen(s); void *p = malloc(len+1); dfsan_memcpy(p, s, len+1); @@ -281,10 +324,16 @@ return static_cast(p); } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncpy, uptr caller_pc, + char *s1, const char *s2, size_t n, dfsan_label s1_label, + dfsan_label s2_label, dfsan_label n_label) + SANITIZER_INTERFACE_ATTRIBUTE char * __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncpy, GET_CALLER_PC(), s1, s2, n, s1_label, + s2_label, n_label); size_t len = strlen(s2); if (len < n) { dfsan_memcpy(s1, s2, len+1); @@ -503,9 +552,15 @@ return ret; } +DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcpy, uptr caller_pc, char *dest, + const char *src, dfsan_label dst_label, + dfsan_label src_label) + SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label, dfsan_label src_label, dfsan_label *ret_label) { + CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcpy, GET_CALLER_PC(), dest, src, dst_label, + src_label); char *ret = strcpy(dest, src); if (ret) { internal_memcpy(shadow_for(dest), shadow_for(src), Index: lib/dfsan/done_abilist.txt =================================================================== --- lib/dfsan/done_abilist.txt +++ lib/dfsan/done_abilist.txt @@ -6,6 +6,8 @@ ############################################################################### fun:dfsan_union=uninstrumented fun:dfsan_union=discard +fun:dfsan_reset=uninstrumented +fun:dfsan_reset=discard fun:dfsan_create_label=uninstrumented fun:dfsan_create_label=discard fun:dfsan_set_label=uninstrumented Index: test/dfsan/reset.cc =================================================================== --- /dev/null +++ test/dfsan/reset.cc @@ -0,0 +1,26 @@ +// RUN: %clang_dfsan %s -o %t && %run %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && %run %t + +// Tests that dfsan is reset correctly in single threaded code. + +#include + +#include + +void foo() { + int i = 1; + int j = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + dfsan_label j_label = dfsan_create_label("j", 0); + dfsan_add_label(j_label, &j, sizeof(j)); +} + +int main(void) { + foo(); + assert(dfsan_get_label_count() == 2); + dfsan_reset(); + assert(dfsan_get_label_count() == 0); + + return 0; +} Index: test/dfsan/reset_multithread.cc =================================================================== --- /dev/null +++ test/dfsan/reset_multithread.cc @@ -0,0 +1,30 @@ +// RUN: %clang_dfsan %s -o %t && %run %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi %s -o %t && %run %t +// XFAIL: * +// Tests that dfsan runtime is reset can be violated in multithreaded settings. + +#include + +#include +#include + +void *baz(void* unused) { + for(int i = 0; i < 1000000000; i++) { + for(int k = 0; k < 100; k++) { + int j = 1; + dfsan_label j_label = dfsan_create_label("j", 0); + dfsan_set_label(j_label, &j, sizeof(j)); + } + dfsan_reset(); + assert(dfsan_get_label_count() == 0); + } +} + +int main(void) { + pthread_t t1, t2; + pthread_create(&t1, NULL, baz, NULL); + pthread_create(&t2, NULL, baz, NULL); + pthread_join(t1, NULL); + pthread_join(t2, NULL); + return 0; +}