Files
clang-p2996/compiler-rt/test/dfsan/sigaction.c
Jianzhou Zhao e1a4322f81 [dfsan] Clean TLS after sigaction callbacks
DFSan uses TLS to pass metadata of arguments and return values. When an
instrumented function accesses the TLS, if a signal callback happens, and
the callback calls other instrumented functions with updating the same TLS,
the TLS is in an inconsistent state after the callback ends. This may cause
either under-tainting or over-tainting.

This fix follows MSan's workaround.
  cb22c67a21
It simply resets TLS at restore. This prevents from over-tainting. Although
under-tainting may still happen, a taint flow can be found eventually if we
run a DFSan-instrumented program multiple times. The alternative option is
saving the entire TLS. However the TLS storage takes 2k bytes, and signal calls
could be nested. So it does not seem worth.

This diff fixes sigaction. A following diff will be fixing signal.

Reviewed-by: morehouse

Differential Revision: https://reviews.llvm.org/D95642
2021-02-02 22:07:17 +00:00

50 lines
1.1 KiB
C

// RUN: %clang_dfsan -DUSE_SIGNAL_ACTION -mllvm -dfsan-fast-16-labels=true %s -o %t && \
// RUN: %run %t
// RUN: %clang_dfsan -mllvm -dfsan-fast-16-labels=true %s -o %t && %run %t
#include <sanitizer/dfsan_interface.h>
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
volatile int x;
volatile int z = 1;
void SignalHandler(int signo) {
assert(dfsan_get_label(signo) == 0);
x = z;
}
void SignalAction(int signo, siginfo_t *si, void *uc) {
assert(dfsan_get_label(signo) == 0);
assert(dfsan_get_label(si) == 0);
assert(dfsan_get_label(uc) == 0);
assert(0 == dfsan_read_label(si, sizeof(*si)));
assert(0 == dfsan_read_label(uc, sizeof(ucontext_t)));
x = z;
}
int main(int argc, char *argv[]) {
dfsan_set_label(8, (void *)&z, sizeof(z));
struct sigaction sa = {};
#ifdef USE_SIGNAL_ACTION
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SignalAction;
#else
sa.sa_handler = SignalHandler;
#endif
int r = sigaction(SIGHUP, &sa, NULL);
assert(dfsan_get_label(r) == 0);
kill(getpid(), SIGHUP);
signal(SIGHUP, SIG_DFL);
assert(x == 1);
return 0;
}