Show signal sender for SI_FROMUSER signals.
Suicide doesn't change:
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
But homicide now looks like this (this is `sleep 666` killed by
`kill -SEGV` as root:
signal 11 (SIGSEGV), code 0 (SI_USER from pid 4446, uid 0), fault addr --------
Bug: http://b/78594105
Test: manual
Change-Id: I8c2feafba8cc5a3db85e8250004d428a464c5d9e
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 05e6efa..c07a34a 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -169,24 +169,26 @@
return;
}
- const char* signal_name = get_signame(info->si_signo);
- bool has_address = signal_has_si_addr(info->si_signo, info->si_code);
-
- // Many signals don't have an address.
+ // Many signals don't have an address or sender.
char addr_desc[32] = ""; // ", fault addr 0x1234"
- if (has_address) {
+ if (signal_has_si_addr(info)) {
async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
}
+ pid_t self_pid = __getpid();
+ char sender_desc[32] = {}; // " from pid 1234, uid 666"
+ if (signal_has_sender(info, self_pid)) {
+ get_signal_sender(sender_desc, sizeof(sender_desc), info);
+ }
char main_thread_name[MAX_TASK_NAME_LEN + 1];
if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
}
- async_safe_format_log(
- ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s), code %d (%s)%s in tid %d (%s), pid %d (%s)",
- info->si_signo, signal_name, info->si_code, get_sigcode(info->si_signo, info->si_code),
- addr_desc, __gettid(), thread_name, __getpid(), main_thread_name);
+ async_safe_format_log(ANDROID_LOG_FATAL, "libc",
+ "Fatal signal %d (%s), code %d (%s%s)%s in tid %d (%s), pid %d (%s)",
+ info->si_signo, get_signame(info), info->si_code, get_sigcode(info),
+ sender_desc, addr_desc, __gettid(), thread_name, self_pid, main_thread_name);
}
/*
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7b04e71..7c5304e 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -74,8 +74,10 @@
void drop_capabilities();
-bool signal_has_si_addr(int si_signo, int si_code);
-const char* get_signame(int sig);
-const char* get_sigcode(int signo, int code);
+bool signal_has_sender(const siginfo_t*, pid_t caller_pid);
+bool signal_has_si_addr(const siginfo_t*);
+void get_signal_sender(char* buf, size_t n, const siginfo_t*);
+const char* get_signame(const siginfo_t*);
+const char* get_sigcode(const siginfo_t*);
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index af8072e..e11be1e 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -102,18 +102,24 @@
if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
}
-static void dump_signal_info(log_t* log, const siginfo_t* si) {
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info) {
char addr_desc[32]; // ", fault addr 0x1234"
- if (signal_has_si_addr(si->si_signo, si->si_code)) {
- snprintf(addr_desc, sizeof(addr_desc), "%p", si->si_addr);
+ if (signal_has_si_addr(thread_info.siginfo)) {
+ snprintf(addr_desc, sizeof(addr_desc), "%p", thread_info.siginfo->si_addr);
} else {
snprintf(addr_desc, sizeof(addr_desc), "--------");
}
- _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", si->si_signo,
- get_signame(si->si_signo), si->si_code, get_sigcode(si->si_signo, si->si_code), addr_desc);
+ char sender_desc[32] = {}; // " from pid 1234, uid 666"
+ if (signal_has_sender(thread_info.siginfo, thread_info.pid)) {
+ get_signal_sender(sender_desc, sizeof(sender_desc), thread_info.siginfo);
+ }
- dump_probable_cause(log, si);
+ _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
+ thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
+ thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
+
+ dump_probable_cause(log, thread_info.siginfo);
}
static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -412,7 +418,7 @@
dump_thread_info(log, thread_info);
if (thread_info.siginfo) {
- dump_signal_info(log, thread_info.siginfo);
+ dump_signal_info(log, thread_info);
}
if (primary_thread) {
@@ -442,7 +448,7 @@
if (map) {
uint64_t addr = 0;
siginfo_t* si = thread_info.siginfo;
- if (signal_has_si_addr(si->si_signo, si->si_code)) {
+ if (signal_has_si_addr(si)) {
addr = reinterpret_cast<uint64_t>(si->si_addr);
}
dump_all_maps(log, map, process_memory, addr);
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 1ad1800..1f6f3c8 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -254,13 +254,13 @@
}
}
-bool signal_has_si_addr(int si_signo, int si_code) {
+bool signal_has_si_addr(const siginfo_t* si) {
// Manually sent signals won't have si_addr.
- if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+ if (si->si_code == SI_USER || si->si_code == SI_QUEUE || si->si_code == SI_TKILL) {
return false;
}
- switch (si_signo) {
+ switch (si->si_signo) {
case SIGBUS:
case SIGFPE:
case SIGILL:
@@ -272,8 +272,16 @@
}
}
-const char* get_signame(int sig) {
- switch (sig) {
+bool signal_has_sender(const siginfo_t* si, pid_t caller_pid) {
+ return SI_FROMUSER(si) && (si->si_pid != 0) && (si->si_pid != caller_pid);
+}
+
+void get_signal_sender(char* buf, size_t n, const siginfo_t* si) {
+ snprintf(buf, n, " from pid %d, uid %d", si->si_pid, si->si_uid);
+}
+
+const char* get_signame(const siginfo_t* si) {
+ switch (si->si_signo) {
case SIGABRT: return "SIGABRT";
case SIGBUS: return "SIGBUS";
case SIGFPE: return "SIGFPE";
@@ -290,11 +298,11 @@
}
}
-const char* get_sigcode(int signo, int code) {
+const char* get_sigcode(const siginfo_t* si) {
// Try the signal-specific codes...
- switch (signo) {
+ switch (si->si_signo) {
case SIGILL:
- switch (code) {
+ switch (si->si_code) {
case ILL_ILLOPC: return "ILL_ILLOPC";
case ILL_ILLOPN: return "ILL_ILLOPN";
case ILL_ILLADR: return "ILL_ILLADR";
@@ -307,7 +315,7 @@
static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
break;
case SIGBUS:
- switch (code) {
+ switch (si->si_code) {
case BUS_ADRALN: return "BUS_ADRALN";
case BUS_ADRERR: return "BUS_ADRERR";
case BUS_OBJERR: return "BUS_OBJERR";
@@ -317,7 +325,7 @@
static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
break;
case SIGFPE:
- switch (code) {
+ switch (si->si_code) {
case FPE_INTDIV: return "FPE_INTDIV";
case FPE_INTOVF: return "FPE_INTOVF";
case FPE_FLTDIV: return "FPE_FLTDIV";
@@ -330,7 +338,7 @@
static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
break;
case SIGSEGV:
- switch (code) {
+ switch (si->si_code) {
case SEGV_MAPERR: return "SEGV_MAPERR";
case SEGV_ACCERR: return "SEGV_ACCERR";
#if defined(SEGV_BNDERR)
@@ -350,21 +358,21 @@
break;
#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
case SIGSYS:
- switch (code) {
+ switch (si->si_code) {
case SYS_SECCOMP: return "SYS_SECCOMP";
}
static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
break;
#endif
case SIGTRAP:
- switch (code) {
+ switch (si->si_code) {
case TRAP_BRKPT: return "TRAP_BRKPT";
case TRAP_TRACE: return "TRAP_TRACE";
case TRAP_BRANCH: return "TRAP_BRANCH";
case TRAP_HWBKPT: return "TRAP_HWBKPT";
}
- if ((code & 0xff) == SIGTRAP) {
- switch ((code >> 8) & 0xff) {
+ if ((si->si_code & 0xff) == SIGTRAP) {
+ switch ((si->si_code >> 8) & 0xff) {
case PTRACE_EVENT_FORK:
return "PTRACE_EVENT_FORK";
case PTRACE_EVENT_VFORK:
@@ -387,7 +395,7 @@
break;
}
// Then the other codes...
- switch (code) {
+ switch (si->si_code) {
case SI_USER: return "SI_USER";
case SI_KERNEL: return "SI_KERNEL";
case SI_QUEUE: return "SI_QUEUE";