From 1db6f2db499490e125a92e2c859a6dc3bef81d72 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Tue, 2 Oct 2012 13:53:13 -0700 Subject: [PATCH] Test flags before using "info" Our debugger signal catcher expects to receive three args, but if somebody cleared SA_SIGINFO we only get one, and bad things happen when we try to use the second one. Test to see if SA_SIGINFO is still set before we try to use the argument. (cherry-pick of f84bc8d6f6368f1c846124a8168761ee8cc589c0.) Bug: 7272866 Change-Id: I69a65c25e833aea70acb78f9ba40ed93308583e6 --- linker/debugger.c | 58 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/linker/debugger.c b/linker/debugger.c index dde66f353..e4d4ae901 100644 --- a/linker/debugger.c +++ b/linker/debugger.c @@ -29,14 +29,10 @@ #include #include #include -#include +#include #include -#include #include #include - -#include "linker.h" - #include #include @@ -113,11 +109,15 @@ static int socket_abstract_client(const char *name, int type) #include <../libc/private/logd.h> /* - * Writes a summary of the signal to the log file. + * Writes a summary of the signal to the log file. We do this so that, if + * for some reason we're not able to contact debuggerd, there is still some + * indication of the failure in the log. * * We could be here as a result of native heap corruption, or while a * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. + * + * "info" will be NULL if the siginfo_t information was not available. */ static void logSignalSummary(int signum, const siginfo_t* info) { @@ -145,13 +145,45 @@ static void logSignalSummary(int signum, const siginfo_t* info) // implies that 16 byte names are not. threadname[MAX_TASK_NAME_LEN] = 0; } - format_buffer(buffer, sizeof(buffer), - "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)", - signum, signame, info->si_addr, info->si_code, gettid(), threadname); + if (info != NULL) { + format_buffer(buffer, sizeof(buffer), + "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)", + signum, signame, info->si_addr, info->si_code, gettid(), threadname); + } else { + format_buffer(buffer, sizeof(buffer), + "Fatal signal %d (%s), thread %d (%s)", + signum, signame, gettid(), threadname); + } __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer); } +/* + * Returns true if the handler for signal "signum" has SA_SIGINFO set. + */ +static bool haveSiginfo(int signum) +{ + struct sigaction oldact, newact; + + memset(&newact, 0, sizeof(newact)); + newact.sa_handler = SIG_DFL; + newact.sa_flags = SA_RESTART; + sigemptyset(&newact.sa_mask); + + if (sigaction(signum, &newact, &oldact) < 0) { + __libc_android_log_write(ANDROID_LOG_FATAL, "libc", + "Failed testing for SA_SIGINFO"); + return 0; + } + bool ret = (oldact.sa_flags & SA_SIGINFO) != 0; + + if (sigaction(signum, &oldact, NULL) < 0) { + __libc_android_log_write(ANDROID_LOG_FATAL, "libc", + "Restore failed in test for SA_SIGINFO"); + } + return ret; +} + /* * Catches fatal signals so we can ask debuggerd to ptrace us before * we crash. @@ -162,6 +194,14 @@ void debugger_signal_handler(int n, siginfo_t* info, void* unused __attribute__( unsigned tid; int s; + /* + * It's possible somebody cleared the SA_SIGINFO flag, which would mean + * our "info" arg holds an undefined value. + */ + if (!haveSiginfo(n)) { + info = NULL; + } + logSignalSummary(n, info); tid = gettid();