From f72b9c6ff4b6c48d4a2239c7da31e5dbf220c440 Mon Sep 17 00:00:00 2001 From: "digit@chromium.org" Date: Tue, 9 Oct 2012 18:03:25 +0000 Subject: Make Linux signal handler more robust. Breakpad can be used on processes where a mistaken library saves then restores one of our signal handlers with 'signal' instead of 'sigaction'. This loses the SA_SIGINFO flag associated with the Breakpad handler, and in some cases (e.g. Android/ARM kernels), the values of the 'info' and 'uc' parameters that ExceptionHandler::SignalHandler() receives will be completely bogus, leading to a crash when the function is executed (and of course, no minidump generation). To work-around this, have SignalHandler() check the state of the flag. If it is incorrectly unset, re-register with 'sigaction' and the correct flag, then return. The signal will be re-thrown, and this time the function will be called with the correct values. Review URL: https://breakpad.appspot.com/481002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1067 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/linux/handler/exception_handler.cc | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/client/linux/handler/exception_handler.cc') diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index aad2a0e0..9a56c14b 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -292,6 +292,35 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { // All the exception signals are blocked at this point. pthread_mutex_lock(&handler_stack_mutex_); + // Sometimes, Breakpad runs inside a process where some other buggy code + // saves and restores signal handlers temporarily with 'signal' + // instead of 'sigaction'. This loses the SA_SIGINFO flag associated + // with this function. As a consequence, the values of 'info' and 'uc' + // become totally bogus, generally inducing a crash. + // + // The following code tries to detect this case. When it does, it + // resets the signal handlers with sigaction + SA_SIGINFO and returns. + // This forces the signal to be thrown again, but this time the kernel + // will call the function with the right arguments. + struct sigaction cur_handler; + if (sigaction(sig, NULL, &cur_handler) == 0 && + (cur_handler.sa_flags & SA_SIGINFO) == 0) { + // Reset signal handler with the right flags. + sigemptyset(&cur_handler.sa_mask); + sigaddset(&cur_handler.sa_mask, sig); + + cur_handler.sa_sigaction = SignalHandler; + cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO; + + if (sigaction(sig, &cur_handler, NULL) == -1) { + // When resetting the handler fails, try to reset the + // default one to avoid an infinite loop here. + signal(sig, SIG_DFL); + } + pthread_mutex_unlock(&handler_stack_mutex_); + return; + } + bool handled = false; for (int i = handler_stack_->size() - 1; !handled && i >= 0; --i) { handled = (*handler_stack_)[i]->HandleSignal(sig, info, uc); -- cgit v1.2.1