From 502567f2f5ee10f98a62d1f399628468c5d4388b Mon Sep 17 00:00:00 2001 From: primiano Date: Mon, 1 Dec 2014 04:52:42 -0800 Subject: [PATCH] [android] Fix SIGABRT handling in the WebView crash handler. The WebView fingerprint crash handler introduced in crrev.com/678763005 was failing to cover the case of signals delivered through kill/raise. Conversely to what happens with segfaults, where the kernel keeps invoking the registered SIGSEGV handler, in these other cases the signal needs to be re-enqueued before chaining to the next handler. This is the case of abort(), which internally does a raise(SIGABRT). BUG=437788 Review URL: https://codereview.chromium.org/769843002 Cr-Commit-Position: refs/heads/master@{#306179} --- android_webview/common/aw_crash_handler.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/android_webview/common/aw_crash_handler.cc b/android_webview/common/aw_crash_handler.cc index a6372983b1db..fbd4285b0505 100644 --- a/android_webview/common/aw_crash_handler.cc +++ b/android_webview/common/aw_crash_handler.cc @@ -6,6 +6,9 @@ #include #include +#include +#include +#include #include "base/logging.h" @@ -27,6 +30,14 @@ void AwExceptionHandler(int sig, siginfo_t* info, void* uc) { if (g_crash_msg_ptr != NULL) __android_log_write(ANDROID_LOG_ERROR, "chromium", g_crash_msg_ptr); + // Detect if some buggy code in the embedder did reinstall the handler using + // signal() instead of sigaction() (which would cause |info| to be invalid). + struct sigaction cur_handler; + if (sigaction(sig, NULL, &cur_handler) != 0 || + (cur_handler.sa_flags & SA_SIGINFO) == 0) { + info = NULL; + } + // We served our purpose. Now restore the old crash handlers. If the embedder // did register a custom crash handler, it will be invoked by the kernel after // this function returns. Otherwise, this will end up invoking the default @@ -36,6 +47,17 @@ void AwExceptionHandler(int sig, siginfo_t* info, void* uc) { signal(kExceptionSignals[i], SIG_DFL); } } + + if ((info != NULL && info->si_pid) || sig == SIGABRT) { + // This signal was triggered by somebody sending us the signal with kill(). + // In order to retrigger it, we have to queue a new signal by calling + // kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is + // due to the kernel sending a SIGABRT from a user request via SysRQ. + if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig) < 0) { + // If we failed to kill ourselves resort to terminating uncleanly. + exit(1); + } + } } } // namespace @@ -65,6 +87,7 @@ void RegisterCrashHandler(const std::string& version) { memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); + // Mask all exception signals when we're handling one of them. for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) sigaddset(&sa.sa_mask, kExceptionSignals[i]); -- 2.11.4.GIT