diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2013-04-04 08:22:52 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2013-04-04 08:22:52 +0000 |
commit | 1f8b3538b49407943d5881329cdbb5c9181f68cc (patch) | |
tree | 49a8252b99b3a555a21e32613f9e2877c68b12a6 | |
parent | c01f4f0d4dc95e5b7f9eeb4f921b694181ff3427 (diff) | |
download | bcm5719-llvm-1f8b3538b49407943d5881329cdbb5c9181f68cc.tar.gz bcm5719-llvm-1f8b3538b49407943d5881329cdbb5c9181f68cc.zip |
[msan] Unpoison siginfo_t and ucontext_t in signal handlers.
Add wrappers for all user signal handlers to unpoison the handler's arguments.
llvm-svn: 178754
4 files changed, 135 insertions, 4 deletions
diff --git a/compiler-rt/lib/msan/msan_interceptors.cc b/compiler-rt/lib/msan/msan_interceptors.cc index 17b4bf8c103..00c54f2a5e9 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cc +++ b/compiler-rt/lib/msan/msan_interceptors.cc @@ -824,17 +824,64 @@ INTERCEPTOR(int, getrusage, int who, void *usage) { return res; } -INTERCEPTOR(int, sigaction, int signum, const void *act, void *oldact) { +const int kMaxSignals = 1024; +static uptr sigactions[kMaxSignals]; +static StaticSpinMutex sigactions_mu; + +static void SignalHandler(int signo) { + typedef void (*signal_cb)(int); + signal_cb cb = (signal_cb)sigactions[signo]; + cb(signo); +} + +static void SignalAction(int signo, void *si, void *uc) { + __msan_unpoison(si, __sanitizer::struct_sigaction_sz); + __msan_unpoison(uc, __sanitizer::struct_ucontext_sz); + + typedef void (*sigaction_cb)(int, void *, void *); + sigaction_cb cb = (sigaction_cb)sigactions[signo]; + cb(signo, si, uc); +} + +INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act, + __sanitizer_sigaction *oldact) { ENSURE_MSAN_INITED(); // FIXME: check that *act is unpoisoned. // That requires intercepting all of sigemptyset, sigfillset, etc. - int res = REAL(sigaction)(signum, act, oldact); - if (res == 0) { + SpinMutexLock lock(&sigactions_mu); + CHECK_LT(signo, kMaxSignals); + uptr old_cb = sigactions[signo]; + __sanitizer_sigaction new_act; + __sanitizer_sigaction *pnew_act = act ? &new_act : 0; + if (act) { + internal_memcpy(pnew_act, act, __sanitizer::struct_sigaction_sz); + uptr cb = __sanitizer::__sanitizer_get_sigaction_sa_sigaction(pnew_act); + uptr new_cb = __sanitizer::__sanitizer_get_sigaction_sa_siginfo(pnew_act) ? + (uptr)SignalAction : (uptr)SignalHandler; + if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { + sigactions[signo] = cb; + __sanitizer::__sanitizer_set_sigaction_sa_sigaction(pnew_act, new_cb); + } + } + int res = REAL(sigaction)(signo, pnew_act, oldact); + if (res == 0 && oldact) { __msan_unpoison(oldact, __sanitizer::struct_sigaction_sz); + __sanitizer::__sanitizer_set_sigaction_sa_sigaction(oldact, old_cb); } return res; } +INTERCEPTOR(int, signal, int signo, uptr cb) { + ENSURE_MSAN_INITED(); + CHECK_LT(signo, kMaxSignals); + SpinMutexLock lock(&sigactions_mu); + if (cb != __sanitizer::sig_ign && cb != __sanitizer::sig_dfl) { + sigactions[signo] = cb; + cb = (uptr)SignalHandler; + } + return REAL(signal)(signo, cb); +} + extern "C" int pthread_attr_init(void *attr); extern "C" int pthread_attr_destroy(void *attr); extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize); @@ -1069,6 +1116,7 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(dlopen); INTERCEPT_FUNCTION(getrusage); INTERCEPT_FUNCTION(sigaction); + INTERCEPT_FUNCTION(signal); INTERCEPT_FUNCTION(pthread_create); inited = 1; } diff --git a/compiler-rt/lib/msan/tests/msan_test.cc b/compiler-rt/lib/msan/tests/msan_test.cc index 3ae9a286c34..e6612baa0f7 100644 --- a/compiler-rt/lib/msan/tests/msan_test.cc +++ b/compiler-rt/lib/msan/tests/msan_test.cc @@ -960,6 +960,55 @@ TEST(MemorySanitizer, frexp) { EXPECT_NOT_POISONED(x); } +namespace { + +static int cnt; + +void SigactionHandler(int signo, siginfo_t* si, void* uc) { + assert(signo == SIGPROF); + assert(si); + EXPECT_NOT_POISONED(si->si_errno); + EXPECT_NOT_POISONED(si->si_pid); +#if __linux__ +# if defined(__x86_64__) + EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]); +# elif defined(__i386__) + EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]); +# endif +#endif + ++cnt; +} + +TEST(MemorySanitizer, sigaction) { + struct sigaction act = {}; + act.sa_flags |= SA_SIGINFO; + act.sa_sigaction = &SigactionHandler; + sigaction(SIGPROF, &act, 0); + + kill(getpid(), SIGPROF); + + act.sa_flags &= ~SA_SIGINFO; + act.sa_handler = SIG_DFL; + sigaction(SIGPROF, &act, 0); + + act.sa_flags &= ~SA_SIGINFO; + act.sa_handler = SIG_IGN; + sigaction(SIGPROF, &act, 0); + kill(getpid(), SIGPROF); + + act.sa_flags |= SA_SIGINFO; + act.sa_sigaction = &SigactionHandler; + sigaction(SIGPROF, &act, 0); + kill(getpid(), SIGPROF); + + act.sa_flags &= ~SA_SIGINFO; + act.sa_handler = SIG_DFL; + sigaction(SIGPROF, &act, 0); + EXPECT_EQ(2, cnt); +} + +} // namespace + struct StructWithDtor { ~StructWithDtor(); }; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index c640e947767..fd39cb2848e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -29,6 +29,7 @@ #include <sys/time.h> #include <sys/resource.h> #include <sys/socket.h> +#include <sys/ucontext.h> #include <time.h> #if SANITIZER_LINUX @@ -44,6 +45,7 @@ namespace __sanitizer { unsigned struct_tm_sz = sizeof(struct tm); unsigned struct_passwd_sz = sizeof(struct passwd); unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_ucontext_sz = sizeof(struct ucontext); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); @@ -61,6 +63,9 @@ namespace __sanitizer { unsigned struct_statfs64_sz = sizeof(struct statfs64); #endif // SANITIZER_LINUX && !SANITIZER_ANDROID + uptr sig_ign = (uptr)SIG_IGN; + uptr sig_dfl = (uptr)SIG_DFL; + void* __sanitizer_get_msghdr_iov_iov_base(void* msg, int idx) { return ((struct msghdr *)msg)->msg_iov[idx].iov_base; } @@ -76,8 +81,24 @@ namespace __sanitizer { uptr __sanitizer_get_socklen_t(void* socklen_ptr) { return *(socklen_t*)socklen_ptr; } + + uptr __sanitizer_get_sigaction_sa_sigaction(void *act) { + struct sigaction *a = (struct sigaction *)act; + // Check that sa_sigaction and sa_handler are the same. + CHECK((void *)&(a->sa_sigaction) == (void *)&(a->sa_handler)); + return (uptr) a->sa_sigaction; + } + void __sanitizer_set_sigaction_sa_sigaction(void *act, uptr cb) { + struct sigaction *a = (struct sigaction *)act; + a->sa_sigaction = (void (*)(int, siginfo_t *, void *))cb; + } + bool __sanitizer_get_sigaction_sa_siginfo(void *act) { + struct sigaction *a = (struct sigaction *)act; + return a->sa_flags & SA_SIGINFO; + } } // namespace __sanitizer COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); - +COMPILER_CHECK(sizeof(__sanitizer::struct_sigaction_max_sz) >= + sizeof(__sanitizer::struct_sigaction_sz)); #endif // SANITIZER_LINUX || SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 18b41065e82..bdec8e5c21c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -25,6 +25,7 @@ namespace __sanitizer { extern unsigned struct_tm_sz; extern unsigned struct_passwd_sz; extern unsigned struct_sigaction_sz; + extern unsigned struct_ucontext_sz; extern unsigned struct_itimerval_sz; extern unsigned pthread_t_sz; @@ -54,6 +55,18 @@ namespace __sanitizer { char size[pthread_attr_t_max_sz]; // NOLINT void *align; }; + + uptr __sanitizer_get_sigaction_sa_sigaction(void *act); + void __sanitizer_set_sigaction_sa_sigaction(void *act, uptr cb); + bool __sanitizer_get_sigaction_sa_siginfo(void *act); + + const unsigned struct_sigaction_max_sz = 256; + union __sanitizer_sigaction { + char size[struct_sigaction_max_sz]; // NOLINT + }; + + extern uptr sig_ign; + extern uptr sig_dfl; } // namespace __sanitizer #endif |