From 97a98836768f8f0154f8f86e5e14c2bb7e74132e Mon Sep 17 00:00:00 2001 From: Lars Volker Date: Mon, 8 Jan 2018 14:09:07 -0800 Subject: Only restore the signal handler if sigaction has not changed Restoring the signal handler in ExceptionHandler::SignalHandler() can lead to a race in scenarios where multiple threads crash within a short time. This can cause threads to alternately try to write a minidump without ever terminating the process. The first thread to write a minidump will reset the signal handler to the SIG_DFL using signal() in InstallDefaultHandler(). The next thread to execute SignalHandler() will detect this and will reset the signal handler to SignalHandler(). If the first thread takes too long to write its minidump (e.g. when there are many threads), the chances increase that the second thread will enter SignalHandler() before the first one leaves the critical section. After resetting the signal handler, the second thread will fail to write a minidump (since the file already exists) and will try to reset the signal handler to the default by calling RestoreHandlersLocked(). However, in the meantime the first thread will have entered SignalHandler() again and will overwrite it one more time. After that, no further attempts will be made to restore the default signal handler and both threads will continue to re-raise the signal and attempt to write minidump files. This change adds a check to make sure that cur_handler.sa_sigaction is still pointing to SignalHandler() before re-installing the handler. To test this we start a large number of sleeping threads and two threads that will crash simultaneously. Without the fix, this would reproducibly lead to a loop between the two crashing threads. Bug: 752 Change-Id: I784328cfff17ddc7476d6668354570ab867ba405 Reviewed-on: https://chromium-review.googlesource.com/855137 Reviewed-by: Mike Frysinger --- src/client/linux/handler/exception_handler.cc | 1 + 1 file changed, 1 insertion(+) (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 cd94e3b5..a41e8c58 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -353,6 +353,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { // will call the function with the right arguments. struct sigaction cur_handler; if (sigaction(sig, NULL, &cur_handler) == 0 && + cur_handler.sa_sigaction == SignalHandler && (cur_handler.sa_flags & SA_SIGINFO) == 0) { // Reset signal handler with the right flags. sigemptyset(&cur_handler.sa_mask); -- cgit v1.2.1