diff --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp --- a/compiler-rt/lib/dfsan/dfsan.cpp +++ b/compiler-rt/lib/dfsan/dfsan.cpp @@ -708,6 +708,14 @@ return data_label; } +// This function is used if dfsan_get_origin is called when origin tracking is +// off. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfsw_dfsan_get_origin( + long data, dfsan_label data_label, dfsan_label *ret_label) { + *ret_label = 0; + return 0; +} + extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_origin __dfso_dfsan_get_origin( long data, dfsan_label data_label, dfsan_label *ret_label, dfsan_origin data_origin, dfsan_origin *ret_origin) { @@ -847,6 +855,7 @@ dfsan_origin origin_id = o.raw_id(); while (o.isChainedOrigin()) { StackTrace stack; + origin_id = o.raw_id(); o = o.getNextChainedOrigin(&stack); } return origin_id; diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp --- a/compiler-rt/lib/dfsan/dfsan_custom.cpp +++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp @@ -37,10 +37,12 @@ #include #include "dfsan/dfsan.h" +#include "dfsan/dfsan_chained_origin_depot.h" #include "dfsan/dfsan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_stackdepot.h" using namespace __dfsan; @@ -310,6 +312,20 @@ return ret; } +SANITIZER_INTERFACE_ATTRIBUTE size_t __dfso_strlen(const char *s, + dfsan_label s_label, + dfsan_label *ret_label, + dfsan_origin s_origin, + dfsan_origin *ret_origin) { + size_t ret = __dfsw_strlen(s, s_label, ret_label); + if (flags().strict_data_dependencies) { + *ret_origin = 0; + } else { + *ret_origin = dfsan_read_origin_of_first_taint(s, ret + 1); + } + return ret; +} + static void *dfsan_memmove(void *dest, const void *src, size_t n) { dfsan_label *sdest = shadow_for(dest); const dfsan_label *ssrc = shadow_for(src); @@ -456,7 +472,8 @@ static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *start_routine_trampoline, void *start_routine, void *arg, - dfsan_label *ret_label) { + dfsan_label *ret_label, + bool track_origins = false) { pthread_attr_t myattr; if (!attr) { pthread_attr_init(&myattr); @@ -466,8 +483,9 @@ // Ensure that the thread stack is large enough to hold all TLS data. AdjustStackSize((void *)(const_cast(attr))); - DFsanThread *t = DFsanThread::Create(start_routine_trampoline, - (thread_callback_t)start_routine, arg); + DFsanThread *t = + DFsanThread::Create(start_routine_trampoline, + (thread_callback_t)start_routine, arg, track_origins); int res = pthread_create(thread, attr, DFsanThreadStartFunc, t); if (attr == &myattr) @@ -487,6 +505,22 @@ start_routine, arg, ret_label); } +SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_create( + pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine_trampoline)(void *, void *, dfsan_label, + dfsan_label *, dfsan_origin, + dfsan_origin *), + void *start_routine, void *arg, dfsan_label thread_label, + dfsan_label attr_label, dfsan_label start_routine_label, + dfsan_label arg_label, dfsan_label *ret_label, dfsan_origin thread_origin, + dfsan_origin attr_origin, dfsan_origin start_routine_origin, + dfsan_origin arg_origin, dfsan_origin *ret_origin) { + int rv = dfsan_pthread_create(thread, attr, (void *)start_routine_trampoline, + start_routine, arg, ret_label, true); + *ret_origin = 0; + return rv; +} + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_join(pthread_t thread, void **retval, dfsan_label thread_label, @@ -499,6 +533,17 @@ return ret; } +SANITIZER_INTERFACE_ATTRIBUTE int __dfso_pthread_join( + pthread_t thread, void **retval, dfsan_label thread_label, + dfsan_label retval_label, dfsan_label *ret_label, + dfsan_origin thread_origin, dfsan_origin retval_origin, + dfsan_origin *ret_origin) { + int ret = __dfsw_pthread_join(thread, retval, thread_label, retval_label, + ret_label); + *ret_origin = 0; + return ret; +} + struct dl_iterate_phdr_info { int (*callback_trampoline)(void *callback, struct dl_phdr_info *info, size_t size, void *data, dfsan_label info_label, @@ -872,6 +917,15 @@ return ret; } +SANITIZER_INTERFACE_ATTRIBUTE +int __dfso_sigemptyset(sigset_t *set, dfsan_label set_label, + dfsan_label *ret_label, dfsan_origin set_origin, + dfsan_origin *ret_origin) { + int ret = __dfsw_sigemptyset(set, set_label, ret_label); + *ret_origin = 0; + return ret; +} + class SignalHandlerScope { public: SignalHandlerScope() { @@ -988,11 +1042,20 @@ } SANITIZER_INTERFACE_ATTRIBUTE -sighandler_t __dfsw_signal(int signum, - void *(*handler_trampoline)(void *, int, dfsan_label, - dfsan_label *), - sighandler_t handler, dfsan_label signum_label, - dfsan_label handler_label, dfsan_label *ret_label) { +int __dfso_sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact, dfsan_label signum_label, + dfsan_label act_label, dfsan_label oldact_label, + dfsan_label *ret_label, dfsan_origin signum_origin, + dfsan_origin act_origin, dfsan_origin oldact_origin, + dfsan_origin *ret_origin) { + int ret = __dfsw_sigaction(signum, act, oldact, signum_label, act_label, + oldact_label, ret_label); + *ret_origin = 0; + return ret; +} + +static sighandler_t dfsan_signal(int signum, sighandler_t handler, + dfsan_label *ret_label) { CHECK_LT(signum, kMaxSignals); SignalSpinLocker lock; uptr old_cb = atomic_load(&sigactions[signum], memory_order_relaxed); @@ -1010,6 +1073,28 @@ return ret; } +SANITIZER_INTERFACE_ATTRIBUTE +sighandler_t __dfsw_signal(int signum, + void *(*handler_trampoline)(void *, int, dfsan_label, + dfsan_label *), + sighandler_t handler, dfsan_label signum_label, + dfsan_label handler_label, dfsan_label *ret_label) { + return dfsan_signal(signum, handler, ret_label); +} + +SANITIZER_INTERFACE_ATTRIBUTE +sighandler_t __dfso_signal( + int signum, + void *(*handler_trampoline)(void *, int, dfsan_label, dfsan_label *, + dfsan_origin, dfsan_origin *), + sighandler_t handler, dfsan_label signum_label, dfsan_label handler_label, + dfsan_label *ret_label, dfsan_origin signum_origin, + dfsan_origin handler_origin, dfsan_origin *ret_origin) { + sighandler_t ret = dfsan_signal(signum, handler, ret_label); + *ret_origin = 0; + return ret; +} + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label, dfsan_label old_ss_label, dfsan_label *ret_label) { @@ -1020,6 +1105,16 @@ return ret; } +SANITIZER_INTERFACE_ATTRIBUTE +int __dfso_sigaltstack(const stack_t *ss, stack_t *old_ss, dfsan_label ss_label, + dfsan_label old_ss_label, dfsan_label *ret_label, + dfsan_origin ss_origin, dfsan_origin old_ss_origin, + dfsan_origin *ret_origin) { + int ret = __dfsw_sigaltstack(ss, old_ss, ss_label, old_ss_label, ret_label); + *ret_origin = 0; + return ret; +} + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz, dfsan_label tv_label, dfsan_label tz_label, @@ -1203,6 +1298,11 @@ int fd, const void *buf, ssize_t count, dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label); +typedef void (*write_origin_trampoline_t)( + void *callback, int fd, const void *buf, ssize_t count, + dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label, + dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin); + // 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 { @@ -1210,6 +1310,11 @@ void *write_callback = nullptr; } write_callback_info; +static struct { + write_origin_trampoline_t write_callback_trampoline = nullptr; + void *write_callback = nullptr; +} write_origin_callback_info; + SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_dfsan_set_write_callback( write_trampoline_t write_callback_trampoline, @@ -1220,6 +1325,15 @@ write_callback_info.write_callback = write_callback; } +SANITIZER_INTERFACE_ATTRIBUTE void __dfso_dfsan_set_write_callback( + write_origin_trampoline_t write_callback_trampoline, void *write_callback, + dfsan_label write_callback_label, dfsan_label *ret_label, + dfsan_origin write_callback_origin, dfsan_origin *ret_origin) { + write_origin_callback_info.write_callback_trampoline = + write_callback_trampoline; + write_origin_callback_info.write_callback = write_callback; +} + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_write(int fd, const void *buf, size_t count, dfsan_label fd_label, dfsan_label buf_label, @@ -1234,6 +1348,23 @@ *ret_label = 0; return write(fd, buf, count); } + +SANITIZER_INTERFACE_ATTRIBUTE int __dfso_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, + dfsan_origin fd_origin, dfsan_origin buf_origin, dfsan_origin count_origin, + dfsan_origin *ret_origin) { + if (write_origin_callback_info.write_callback) { + write_origin_callback_info.write_callback_trampoline( + write_origin_callback_info.write_callback, fd, buf, count, fd_label, + buf_label, count_label, fd_origin, buf_origin, count_origin); + } + + *ret_label = 0; + *ret_origin = 0; + return write(fd, buf, count); +} + } // namespace __dfsan // Type used to extract a dfsan_label with va_arg() @@ -1491,6 +1622,32 @@ return ret; } +static void BeforeFork() { + StackDepotLockAll(); + GetChainedOriginDepot()->LockAll(); +} + +static void AfterFork() { + GetChainedOriginDepot()->UnlockAll(); + StackDepotUnlockAll(); +} + +SANITIZER_INTERFACE_ATTRIBUTE +pid_t __dfsw_fork(dfsan_label *ret_label) { + pid_t pid = fork(); + *ret_label = 0; + return pid; +} + +SANITIZER_INTERFACE_ATTRIBUTE +pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) { + BeforeFork(); + pid_t pid = __dfsw_fork(ret_label); + AfterFork(); + *ret_origin = 0; + return pid; +} + // Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *, diff --git a/compiler-rt/lib/dfsan/dfsan_thread.h b/compiler-rt/lib/dfsan/dfsan_thread.h --- a/compiler-rt/lib/dfsan/dfsan_thread.h +++ b/compiler-rt/lib/dfsan/dfsan_thread.h @@ -24,7 +24,8 @@ // via mmap() and *must* be valid in zero-initialized state. static DFsanThread *Create(void *start_routine_trampoline, - thread_callback_t start_routine, void *arg); + thread_callback_t start_routine, void *arg, + bool track_origins = false); static void TSDDtor(void *tsd); void Destroy(); @@ -54,6 +55,7 @@ void *start_routine_trampoline_; thread_callback_t start_routine_; void *arg_; + bool track_origins_; StackBounds stack_; diff --git a/compiler-rt/lib/dfsan/dfsan_thread.cpp b/compiler-rt/lib/dfsan/dfsan_thread.cpp --- a/compiler-rt/lib/dfsan/dfsan_thread.cpp +++ b/compiler-rt/lib/dfsan/dfsan_thread.cpp @@ -7,13 +7,15 @@ namespace __dfsan { DFsanThread *DFsanThread::Create(void *start_routine_trampoline, - thread_callback_t start_routine, void *arg) { + thread_callback_t start_routine, void *arg, + bool track_origins) { uptr PageSize = GetPageSizeCached(); uptr size = RoundUpTo(sizeof(DFsanThread), PageSize); DFsanThread *thread = (DFsanThread *)MmapOrDie(size, __func__); thread->start_routine_trampoline_ = start_routine_trampoline; thread->start_routine_ = start_routine; thread->arg_ = arg; + thread->track_origins_ = track_origins; thread->destructor_iterations_ = GetPthreadDestructorIterations(); return thread; @@ -57,11 +59,19 @@ typedef void *(*thread_callback_trampoline_t)(void *, void *, dfsan_label, dfsan_label *); + typedef void *(*thread_callback_origin_trampoline_t)( + void *, void *, dfsan_label, dfsan_label *, dfsan_origin, dfsan_origin *); dfsan_label ret_label; - return ((thread_callback_trampoline_t) + if (!track_origins_) + return ((thread_callback_trampoline_t) + start_routine_trampoline_)((void *)start_routine_, arg_, 0, + &ret_label); + + dfsan_origin ret_origin; + return ((thread_callback_origin_trampoline_t) start_routine_trampoline_)((void *)start_routine_, arg_, 0, - &ret_label); + &ret_label, 0, &ret_origin); } DFsanThread::StackBounds DFsanThread::GetStackBounds() const { diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt --- a/compiler-rt/lib/dfsan/done_abilist.txt +++ b/compiler-rt/lib/dfsan/done_abilist.txt @@ -30,6 +30,8 @@ fun:dfsan_flush=discard fun:dfsan_print_origin_trace=uninstrumented fun:dfsan_print_origin_trace=discard +fun:dfsan_get_origin=uninstrumented +fun:dfsan_get_origin=custom fun:dfsan_get_init_origin=uninstrumented fun:dfsan_get_init_origin=discard @@ -270,6 +272,9 @@ fun:asprintf=discard fun:qsort=discard +# fork +fun:fork=custom + ############################################################################### # pthread ############################################################################### diff --git a/compiler-rt/test/dfsan/atomic.cpp b/compiler-rt/test/dfsan/atomic.cpp --- a/compiler-rt/test/dfsan/atomic.cpp +++ b/compiler-rt/test/dfsan/atomic.cpp @@ -1,4 +1,5 @@ // RUN: %clangxx_dfsan -mllvm -dfsan-fast-16-labels=true %s -fno-exceptions -o %t && %run %t +// RUN: %clangxx_dfsan -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -fno-exceptions -o %t && %run %t // // Use -fno-exceptions to turn off exceptions to avoid instrumenting // __cxa_begin_catch, std::terminate and __gxx_personality_v0. diff --git a/compiler-rt/test/dfsan/origin_custom.cpp b/compiler-rt/test/dfsan/origin_custom.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_custom.cpp @@ -0,0 +1,234 @@ +// RUN: %clang_dfsan -DFAST_16_LABELS -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-origins=1 -mllvm -dfsan-combine-pointer-labels-on-load=false -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t +// RUN: %clang_dfsan -DFAST_16_LABELS -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-origins=1 -mllvm -dfsan-combine-pointer-labels-on-load=false %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t + +// Tests custom implementations of various glibc functions. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +dfsan_label i_label = 0; +dfsan_label j_label = 0; +dfsan_label k_label = 0; +dfsan_label m_label = 0; +dfsan_label n_label = 0; +dfsan_label i_j_label = 0; + +#define ASSERT_ZERO_LABEL(data) \ + assert(0 == dfsan_get_label((long)(data))) + +#define ASSERT_READ_ZERO_LABEL(ptr, size) \ + assert(0 == dfsan_read_label(ptr, size)) + +#define ASSERT_LABEL(data, label) \ + assert(label == dfsan_get_label((long)(data))) + +#define ASSERT_READ_LABEL(ptr, size, label) \ + assert(label == dfsan_read_label(ptr, size)) + +#define ASSERT_ZERO_ORIGIN(data) \ + assert(0 == dfsan_get_origin((long)(data))) + +#define ASSERT_ZERO_ORIGINS(ptr, size) \ + for (int i = 0; i < size; ++i) { \ + assert(0 == dfsan_get_origin((long)(((char *)ptr)[i]))); \ + } + +#define ASSERT_ORIGIN(data, origin) \ + assert(origin == dfsan_get_origin((long)(data))) + +#define ASSERT_ORIGINS(ptr, size, origin) \ + for (int i = 0; i < size; ++i) { \ + assert(origin == dfsan_get_origin((long)(((char *)ptr)[i]))); \ + } + +#define ASSERT_INIT_ORIGIN(ptr, origin) \ + assert(origin == dfsan_get_init_origin(ptr)) + +#define ASSERT_INIT_ORIGIN_EQ_ORIGIN(ptr, data) \ + assert(dfsan_get_origin((long)(data)) == dfsan_get_init_origin(ptr)) + +#define ASSERT_INIT_ORIGINS(ptr, size, origin) \ + for (int i = 0; i < size; ++i) { \ + assert(origin == dfsan_get_init_origin(&((char *)ptr)[i])); \ + } + +#define ASSERT_EQ_ORIGIN(data1, data2) \ + assert(dfsan_get_origin((long)(data1)) == dfsan_get_origin((long)(data2))) + +#define DEFINE_AND_SAVE_ORIGINS(val) \ + dfsan_origin val##_o[sizeof(val)]; \ + for (int i = 0; i < sizeof(val); ++i) \ + val##_o[i] = dfsan_get_origin((long)(((char *)(&val))[i])); + +#define SAVE_ORIGINS(val) \ + for (int i = 0; i < sizeof(val); ++i) \ + val##_o[i] = dfsan_get_origin((long)(((char *)(&val))[i])); + +#define ASSERT_SAVED_ORIGINS(val) \ + for (int i = 0; i < sizeof(val); ++i) \ + ASSERT_ORIGIN(((char *)(&val))[i], val##_o[i]); + +#define DEFINE_AND_SAVE_N_ORIGINS(val, n) \ + dfsan_origin val##_o[n]; \ + for (int i = 0; i < n; ++i) \ + val##_o[i] = dfsan_get_origin((long)(val[i])); + +#define ASSERT_SAVED_N_ORIGINS(val, n) \ + for (int i = 0; i < n; ++i) \ + ASSERT_ORIGIN(val[i], val##_o[i]); + +void test_strlen() { + char str1[] = "str1"; + dfsan_set_label(i_label, &str1[3], 1); + + int rv = strlen(str1); + assert(rv == 4); +#ifdef STRICT_DATA_DEPENDENCIES + ASSERT_ZERO_LABEL(rv); + ASSERT_ZERO_ORIGIN(rv); +#else + ASSERT_LABEL(rv, i_label); + ASSERT_EQ_ORIGIN(rv, str1[3]); +#endif +} + +void test_sigemptyset() { + sigset_t set; + dfsan_set_label(j_label, &set, 1); + DEFINE_AND_SAVE_ORIGINS(set) + int ret = sigemptyset(&set); + assert(ret == 0); + ASSERT_ZERO_LABEL(ret); + ASSERT_ZERO_ORIGIN(ret); + ASSERT_READ_ZERO_LABEL(&set, sizeof(set)); + ASSERT_SAVED_ORIGINS(set) +} + +void test_sigaction() { + struct sigaction oldact; + dfsan_set_label(j_label, &oldact, 1); + DEFINE_AND_SAVE_ORIGINS(oldact) + int ret = sigaction(SIGUSR1, NULL, &oldact); + assert(ret == 0); + ASSERT_ZERO_LABEL(ret); + ASSERT_ZERO_ORIGIN(ret); + ASSERT_READ_ZERO_LABEL(&oldact, sizeof(oldact)); + ASSERT_SAVED_ORIGINS(oldact) +} + +static void SignalHandler(int signo) {} + +void test_signal() { + sighandler_t old_signal_handler = signal(SIGHUP, SignalHandler); + ASSERT_ZERO_LABEL(old_signal_handler); + ASSERT_ZERO_ORIGIN(old_signal_handler); + (void)signal(SIGHUP, old_signal_handler); +} + +void test_sigaltstack() { + stack_t old_altstack = {}; + dfsan_set_label(j_label, &old_altstack, sizeof(old_altstack)); + DEFINE_AND_SAVE_ORIGINS(old_altstack) + int ret = sigaltstack(NULL, &old_altstack); + assert(ret == 0); + ASSERT_ZERO_LABEL(ret); + ASSERT_ZERO_ORIGIN(ret); + ASSERT_READ_ZERO_LABEL(&old_altstack, sizeof(old_altstack)); + ASSERT_SAVED_ORIGINS(old_altstack) +} + +void *pthread_create_test_cb(void *p) { + assert(p == (void *)1); + ASSERT_ZERO_LABEL(p); + return (void *)2; +} + +void test_pthread_create() { + pthread_t pt; + pthread_create(&pt, 0, pthread_create_test_cb, (void *)1); + void *cbrv; + dfsan_set_label(i_label, &cbrv, sizeof(cbrv)); + DEFINE_AND_SAVE_ORIGINS(cbrv) + int ret = pthread_join(pt, &cbrv); + assert(ret == 0); + assert(cbrv == (void *)2); + ASSERT_ZERO_LABEL(ret); + ASSERT_ZERO_LABEL(cbrv); + ASSERT_ZERO_ORIGIN(ret); + ASSERT_SAVED_ORIGINS(cbrv); +} + +void test_write() { + int fd = open("/dev/null", O_WRONLY); + + char buf[] = "a string"; + int len = strlen(buf); + + // The result of a write always unlabeled. + int res = write(fd, buf, len); + assert(res > 0); + ASSERT_ZERO_LABEL(res); + + // Label all arguments to write(). + dfsan_set_label(i_label, &(buf[3]), 1); + dfsan_set_label(j_label, &fd, sizeof(fd)); + dfsan_set_label(i_label, &len, sizeof(len)); + + // The value returned by write() should have no label. + res = write(fd, buf, len); + ASSERT_ZERO_LABEL(res); + ASSERT_ZERO_ORIGIN(res); + + close(fd); +} + +int main(void) { +#ifdef FAST_16_LABELS + i_label = 1; + j_label = 2; + k_label = 4; + m_label = 8; + n_label = 16; +#else + i_label = dfsan_create_label("i", 0); + j_label = dfsan_create_label("j", 0); + k_label = dfsan_create_label("k", 0); + m_label = dfsan_create_label("m", 0); + n_label = dfsan_create_label("n", 0); +#endif + i_j_label = dfsan_union(i_label, j_label); + assert(i_j_label != i_label); + assert(i_j_label != j_label); + assert(i_j_label != k_label); + + test_pthread_create(); + test_sigaction(); + test_signal(); + test_sigaltstack(); + test_sigemptyset(); + test_strlen(); + test_write(); +} diff --git a/compiler-rt/test/dfsan/origin_fork.cpp b/compiler-rt/test/dfsan/origin_fork.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_fork.cpp @@ -0,0 +1,103 @@ +// Test that chained origins are fork-safe. +// Run a number of threads that create new chained origins, then fork +// and verify that origin reads do not deadlock in the child process. +// +// RUN: %clangxx_dfsan -std=c++11 -mllvm -dfsan-fast-16-labels=true %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// +// RUN: %clangxx_dfsan -std=c++11 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t +// RUN: DFSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int done; + +void copy_uninit_thread2() { + volatile int x; + volatile int v; + dfsan_set_label(8, (void *)&x, sizeof(x)); + while (true) { + v = x; + x = v; + if (__atomic_load_n(&done, __ATOMIC_RELAXED)) + return; + } +} + +void copy_uninit_thread1(int level) { + if (!level) + copy_uninit_thread2(); + else + copy_uninit_thread1(level - 1); +} + +void *copy_uninit_thread(void *id) { + copy_uninit_thread1((long)id); + return 0; +} + +// Run through stackdepot in the child process. +// If any of the hash table cells are locked, this may deadlock. +void child() { + volatile int x; + volatile int v; + dfsan_set_label(16, (void *)&x, sizeof(x)); + for (int i = 0; i < 10000; ++i) { + v = x; + x = v; + } + write(2, "done\n", 5); +} + +void test() { + const int kThreads = 10; + pthread_t t[kThreads]; + for (int i = 0; i < kThreads; ++i) + pthread_create(&t[i], NULL, copy_uninit_thread, (void *)(long)i); + usleep(100000); + pid_t pid = fork(); + if (pid) { + // parent + __atomic_store_n(&done, 1, __ATOMIC_RELAXED); + pid_t p; + while ((p = wait(NULL)) == -1) { + } + } else { + // child + child(); + } +} + +int main() { + const int kChildren = 20; + for (int i = 0; i < kChildren; ++i) { + pid_t pid = fork(); + if (pid) { + // parent + } else { + test(); + exit(0); + } + } + + for (int i = 0; i < kChildren; ++i) { + pid_t p; + while ((p = wait(NULL)) == -1) { + } + } + + return 0; +} + +// Expect 20 (== kChildren) "done" messages. +// CHECK-COUNT-20: done diff --git a/compiler-rt/test/dfsan/origin_pthread.c b/compiler-rt/test/dfsan/origin_pthread.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_pthread.c @@ -0,0 +1,62 @@ +// RUN: %clang_dfsan -gmlt -DCHECK8 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK8 < %t.out + +// RUN: %clang_dfsan -gmlt -DCHECK16 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true -mllvm -dfsan-instrument-with-call-threshold=0 %s -o %t && \ +// RUN: %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK16 < %t.out + +#include + +#include +#include + +const int kNumThreads = 24; +int volatile x = 0; +int __thread y, z; + +static void *ThreadFn(void *a) { + y = x; + memcpy((void *)&z, (void *)&y, sizeof(y)); +#if defined(CHECK8) + if ((int)a == 8) + dfsan_print_origin_trace(&z, NULL); +#elif defined(CHECK16) + if ((int)a == 16) + dfsan_print_origin_trace(&z, NULL); +#endif + return 0; +} + +int main(void) { + dfsan_set_label(8, &x, sizeof(x)); + + pthread_t t[kNumThreads]; + for (int i = 0; i < kNumThreads; ++i) + pthread_create(&t[i], 0, ThreadFn, (void *)i); + + for (int i = 0; i < kNumThreads; ++i) + pthread_join(t[i], 0); + + return 0; +} + +// CHECK8: Taint value 0x8 {{.*}} origin tracking () +// CHECK8: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK8: #0 {{.*}} in dfs$ThreadFn {{.*}}origin_pthread.c:[[@LINE-26]] + +// CHECK8: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK8: #0 {{.*}} in dfs$ThreadFn {{.*}}origin_pthread.c:[[@LINE-30]] + +// CHECK8: Origin value: {{.*}}, Taint value was created at +// CHECK8: #0 {{.*}} in main {{.*}}origin_pthread.c:[[@LINE-20]] + +// CHECK16: Taint value 0x8 {{.*}} origin tracking () +// CHECK16: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK16: #0 {{.*}} in dfs$ThreadFn {{.*}}origin_pthread.c:[[@LINE-36]] + +// CHECK16: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK16: #0 {{.*}} in dfs$ThreadFn {{.*}}origin_pthread.c:[[@LINE-40]] + +// CHECK16: Origin value: {{.*}}, Taint value was created at +// CHECK16: #0 {{.*}} in main {{.*}}origin_pthread.c:[[@LINE-30]] diff --git a/compiler-rt/test/dfsan/origin_signal_stress_test.cpp b/compiler-rt/test/dfsan/origin_signal_stress_test.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_signal_stress_test.cpp @@ -0,0 +1,63 @@ +// RUN: %clangxx_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true -O0 %s -o %t && %run %t +// RUN: %clangxx_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true -mllvm -dfsan-instrument-with-call-threshold=0 -O0 %s -o %t && %run %t +// +// Test that the state of shadows and origins from a signal handler are consistent. + +#include +#include +#include +#include +#include +#include + +const int kSigCnt = 200; +int x; + +__attribute__((noinline)) int f(int a) { + return a; +} + +__attribute__((noinline)) void g(const dfsan_origin origin) { + int r = f(x); + const dfsan_label r_label = dfsan_get_label(r); + assert(r_label == 8 || r_label == 0); + const dfsan_origin r_origin = dfsan_get_init_origin(&r); + assert(r_origin == origin || r_origin == 0); + return; +} + +int sigcnt; + +void SignalHandler(int signo) { + assert(signo == SIGPROF); + int a = 0; + dfsan_set_label(4, &a, sizeof(a)); + (void)f(a); + ++sigcnt; +} + +int main() { + signal(SIGPROF, SignalHandler); + + itimerval itv; + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 100; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 100; + setitimer(ITIMER_PROF, &itv, NULL); + + dfsan_set_label(8, &x, sizeof(x)); + const dfsan_origin origin = dfsan_get_origin(x); + do { + g(origin); + } while (sigcnt < kSigCnt); + + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 0; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + setitimer(ITIMER_PROF, &itv, NULL); + + signal(SIGPROF, SIG_DFL); + return 0; +} diff --git a/compiler-rt/test/dfsan/origin_with_sigactions.c b/compiler-rt/test/dfsan/origin_with_sigactions.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_with_sigactions.c @@ -0,0 +1,88 @@ +// Check that stores in signal handlers are not recorded in origin history. + +// RUN: %clang_dfsan -gmlt -DUSE_SIGNAL_ACTION -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: not %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK_ACTION < %t.out + +// RUN: %clang_dfsan -gmlt -DUSE_SIGNAL_ACTION -mllvm -msan-instrumentation-with-call-threshold=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: not %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK_ACTION < %t.out + +// RUN: %clang_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: not %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK_HANDLE < %t.out + +// RUN: %clang_dfsan -gmlt -mllvm -msan-instrumentation-with-call-threshold=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: not %run %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK_HANDLE < %t.out + +#include + +#include +#include +#include +#include +#include + +volatile int x, y, u; + +void SignalHandler(int signo) { + y = x; + memcpy((void *)&u, (void *)&y, sizeof(int)); +} + +void SignalAction(int signo, siginfo_t *si, void *uc) { + y = x; + memcpy((void *)&u, (void *)&y, sizeof(int)); +} + +int main(int argc, char *argv[]) { + int volatile z = 1; + dfsan_set_label(8, (void *)&z, sizeof(z)); + x = z; + + struct sigaction psa = {}; +#ifdef USE_SIGNAL_ACTION + psa.sa_flags = SA_SIGINFO; + psa.sa_sigaction = SignalAction; +#else + psa.sa_flags = 0; + psa.sa_handler = SignalHandler; +#endif + sigaction(SIGHUP, &psa, NULL); + kill(getpid(), SIGHUP); + signal(SIGHUP, SIG_DFL); + + assert(x == 1); + assert(y == 1); + assert(u == 1); + + dfsan_print_origin_trace((void *)&u, NULL); + return u; +} + +// CHECK_HANDLE: Taint value 0x8 {{.*}} origin tracking () +// CHECK_HANDLE: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK_HANDLE-NOT: {{.*}} in dfs$SignalHandler {{.*}}origin_with_sigactions.c{{.*}} + + + + + +// CHECK_HANDLE: #0 {{.*}} in main {{.*}}origin_with_sigactions.c:[[@LINE-30]] + +// CHECK_HANDLE: Origin value: {{.*}}, Taint value was created at +// CHECK_HANDLE: #0 {{.*}} in main {{.*}}origin_with_sigactions.c:[[@LINE-34]] + +// CHECK_ACTION: Taint value 0x8 {{.*}} origin tracking +// CHECK_ACTION: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK_HANDLE-NOT: {{.*}} in dfs$SignalAction {{.*}}origin_with_sigactions.c{{.*}} + + + + + +// CHECK_ACTION: #0 {{.*}} in main {{.*}}origin_with_sigactions.c:[[@LINE-43]] + +// CHECK_ACTION: Origin value: {{.*}}, Taint value was created at +// CHECK_ACTION: #0 {{.*}} in main {{.*}}origin_with_sigactions.c:[[@LINE-47]] diff --git a/compiler-rt/test/dfsan/origin_with_signals.cpp b/compiler-rt/test/dfsan/origin_with_signals.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/origin_with_signals.cpp @@ -0,0 +1,45 @@ +// Check that stores in signal handlers are not recorded in origin history. + +// RUN: %clangxx_dfsan -gmlt -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_dfsan -gmlt -mllvm -msan-instrumentation-with-call-threshold=0 -mllvm -dfsan-track-origins=1 -mllvm -dfsan-fast-16-labels=true %s -o %t && \ +// RUN: not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +#include +#include +#include +#include + +volatile int x, y, u; + +void SignalHandler(int signo) { + y = x; + memcpy((void *)&u, (void *)&y, sizeof(int)); +} + +int main(int argc, char *argv[]) { + int volatile z = 2; + dfsan_set_label(8, (void *)&z, sizeof(z)); + x = z; + + signal(SIGHUP, SignalHandler); + kill(getpid(), SIGHUP); + signal(SIGHUP, SIG_DFL); + + dfsan_print_origin_trace((void *)&u, nullptr); + return u; +} + +// CHECK: Taint value 0x8 {{.*}} origin tracking () +// CHECK: Origin value: {{.*}}, Taint value was stored to memory at +// CHECK-NOT: {{.*}} in dfs$SignalHandler {{.*}}origin_with_signals.cpp{{.*}} + +// CHECK: #0 {{.*}} in main {{.*}}origin_with_signals.cpp:[[@LINE-18]] + +// CHECK: Origin value: {{.*}}, Taint value was created at +// CHECK: #0 {{.*}} in main {{.*}}origin_with_signals.cpp:[[@LINE-22]]