summaryrefslogtreecommitdiffstats
path: root/debuggerd
diff options
context:
space:
mode:
authorJosh Gao <jmgao@google.com>2017-03-15 23:23:22 -0700
committerJosh Gao <jmgao@google.com>2017-03-15 23:30:14 -0700
commit57f58f8e4a143f1208593c8b397b9a17d055dad0 (patch)
tree6760dea6ea2582cf8edfc527a0addf525142fca6 /debuggerd
parente7b335b4712bc650c93b5b5777a6f8b1d85ad83f (diff)
downloadcore-57f58f8e4a143f1208593c8b397b9a17d055dad0.tar.gz
core-57f58f8e4a143f1208593c8b397b9a17d055dad0.tar.bz2
core-57f58f8e4a143f1208593c8b397b9a17d055dad0.zip
crash_dump: fetch process/thread names before dropping privileges.
Processes that don't have dumpable set to 1 cannot have their process/thread names read by processes that don't have all of their capabilities. Fetch these names in crash_dump before dropping privileges. Bug: http://b/36237221 Test: debuggerd_test Test: debuggerd -b `pidof android.hardware.bluetooth@1.0-service` Change-Id: I174769e7b3c1ea9f11f9c8cbdff83028a4225783
Diffstat (limited to 'debuggerd')
-rw-r--r--debuggerd/crash_dump.cpp29
-rw-r--r--debuggerd/libdebuggerd/backtrace.cpp66
-rw-r--r--debuggerd/libdebuggerd/include/backtrace.h6
-rw-r--r--debuggerd/libdebuggerd/include/tombstone.h9
-rw-r--r--debuggerd/libdebuggerd/include/utility.h2
-rw-r--r--debuggerd/libdebuggerd/tombstone.cpp79
-rw-r--r--debuggerd/libdebuggerd/utility.cpp18
7 files changed, 109 insertions, 100 deletions
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 38b711ff4..88f390b0e 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <limits>
+#include <map>
#include <memory>
#include <set>
#include <vector>
@@ -36,6 +37,7 @@
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include <log/log.h>
@@ -52,7 +54,21 @@
#include "debuggerd/util.h"
using android::base::unique_fd;
+using android::base::ReadFileToString;
using android::base::StringPrintf;
+using android::base::Trim;
+
+static std::string get_process_name(pid_t pid) {
+ std::string result = "<unknown>";
+ ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &result);
+ return result;
+}
+
+static std::string get_thread_name(pid_t tid) {
+ std::string result = "<unknown>";
+ ReadFileToString(StringPrintf("/proc/%d/comm", tid), &result);
+ return Trim(result);
+}
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
struct stat st;
@@ -253,7 +269,7 @@ int main(int argc, char** argv) {
}
// Seize the siblings.
- std::set<pid_t> attached_siblings;
+ std::map<pid_t, std::string> threads;
{
std::set<pid_t> siblings;
if (!android::procinfo::GetProcessTids(target, &siblings)) {
@@ -269,12 +285,12 @@ int main(int argc, char** argv) {
if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
LOG(WARNING) << attach_error;
} else {
- attached_siblings.insert(sibling_tid);
+ threads.emplace(sibling_tid, get_thread_name(sibling_tid));
}
}
}
- // Collect the backtrace map and open files, while the process still has PR_GET_DUMPABLE=1
+ // Collect the backtrace map, open files, and process/thread names, while we still have caps.
std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
if (!backtrace_map) {
LOG(FATAL) << "failed to create backtrace map";
@@ -284,6 +300,9 @@ int main(int argc, char** argv) {
OpenFilesList open_files;
populate_open_files_list(target, &open_files);
+ std::string process_name = get_process_name(main_tid);
+ threads.emplace(main_tid, get_thread_name(main_tid));
+
// Drop our capabilities now that we've attached to the threads we care about.
drop_capabilities();
@@ -341,10 +360,10 @@ int main(int argc, char** argv) {
std::string amfd_data;
if (backtrace) {
- dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0);
+ dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0);
} else {
engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
- &attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
+ process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr);
}
// We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index df49aef37..334d97f33 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -38,18 +38,7 @@
#include "utility.h"
-static void dump_process_header(log_t* log, pid_t pid) {
- char path[PATH_MAX];
- char procnamebuf[1024];
- char* procname = NULL;
- FILE* fp;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
+static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
@@ -57,8 +46,8 @@ static void dump_process_header(log_t* log, pid_t pid) {
strftime(timestr, sizeof(timestr), "%F %T", &tm);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
- if (procname) {
- _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
+ if (process_name) {
+ _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name);
}
_LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
@@ -67,28 +56,13 @@ static void dump_process_footer(log_t* log, pid_t pid) {
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
-static void log_thread_name(log_t* log, pid_t tid) {
- FILE* fp;
- char buf[1024];
- char path[PATH_MAX];
- char* threadname = NULL;
-
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- if ((fp = fopen(path, "r"))) {
- threadname = fgets(buf, sizeof(buf), fp);
- fclose(fp);
- if (threadname) {
- size_t len = strlen(threadname);
- if (len && threadname[len - 1] == '\n') {
- threadname[len - 1] = '\0';
- }
- }
- }
- _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+static void log_thread_name(log_t* log, pid_t tid, const char* thread_name) {
+ _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread_name, tid);
}
-static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) {
- log_thread_name(log, tid);
+static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
+ const std::string& thread_name) {
+ log_thread_name(log, tid, thread_name.c_str());
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
if (backtrace->Unwind(0)) {
@@ -99,17 +73,21 @@ static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) {
}
}
-void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, std::string* amfd_data) {
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, std::string* amfd_data) {
log_t log;
log.tfd = fd;
log.amfd_data = amfd_data;
- dump_process_header(&log, pid);
- dump_thread(&log, map, pid, tid);
+ dump_process_header(&log, pid, process_name.c_str());
+ dump_thread(&log, map, pid, tid, threads.find(tid)->second.c_str());
- for (pid_t sibling : siblings) {
- dump_thread(&log, map, pid, sibling);
+ for (const auto& it : threads) {
+ pid_t thread_tid = it.first;
+ const std::string& thread_name = it.second;
+ if (thread_tid != tid) {
+ dump_thread(&log, map, pid, thread_tid, thread_name.c_str());
+ }
}
dump_process_footer(&log, pid);
@@ -123,7 +101,9 @@ void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext) {
log.tfd = output_fd;
log.amfd_data = nullptr;
- log_thread_name(&log, tid);
+ char thread_name[16];
+ read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
+ log_thread_name(&log, tid, thread_name);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
if (backtrace->Unwind(0, ucontext)) {
@@ -139,7 +119,9 @@ void dump_backtrace_header(int output_fd) {
log.tfd = output_fd;
log.amfd_data = nullptr;
- dump_process_header(&log, getpid());
+ char process_name[128];
+ read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
+ dump_process_header(&log, getpid(), process_name);
}
void dump_backtrace_footer(int output_fd) {
diff --git a/debuggerd/libdebuggerd/include/backtrace.h b/debuggerd/libdebuggerd/include/backtrace.h
index 5bfdac8fc..fe738f1c7 100644
--- a/debuggerd/libdebuggerd/include/backtrace.h
+++ b/debuggerd/libdebuggerd/include/backtrace.h
@@ -20,7 +20,7 @@
#include <sys/types.h>
#include <sys/ucontext.h>
-#include <set>
+#include <map>
#include <string>
#include "utility.h"
@@ -30,8 +30,8 @@ class BacktraceMap;
// Dumps a backtrace using a format similar to what Dalvik uses so that the result
// can be intermixed in a bug report.
-void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, std::string* amfd_data);
+void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, std::string* amfd_data);
/* Dumps the backtrace in the backtrace data structure to the log. */
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
diff --git a/debuggerd/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/tombstone.h
index d2a4a4bb7..79743b61c 100644
--- a/debuggerd/libdebuggerd/include/tombstone.h
+++ b/debuggerd/libdebuggerd/include/tombstone.h
@@ -20,7 +20,8 @@
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
-#include <set>
+
+#include <map>
#include <string>
#include "open_files_list.h"
@@ -34,9 +35,9 @@ class BacktraceMap;
int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>* siblings, uintptr_t abort_msg_address,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+ pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
std::string* amfd_data);
void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
diff --git a/debuggerd/libdebuggerd/include/utility.h b/debuggerd/libdebuggerd/include/utility.h
index bbc45468b..e5e510634 100644
--- a/debuggerd/libdebuggerd/include/utility.h
+++ b/debuggerd/libdebuggerd/include/utility.h
@@ -83,4 +83,6 @@ bool wait_for_signal(pid_t tid, siginfo_t* siginfo);
void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
+void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
+
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index c05ccc358..c23da4415 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -32,8 +32,10 @@
#include <memory>
#include <string>
-#include <android/log.h>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android/log.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <cutils/properties.h>
@@ -247,41 +249,16 @@ static void dump_signal_info(log_t* log, pid_t tid) {
dump_signal_info(log, &si);
}
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
- char path[64];
- char threadnamebuf[1024];
- char* threadname = nullptr;
- FILE *fp;
-
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- if ((fp = fopen(path, "r"))) {
- threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
- fclose(fp);
- if (threadname) {
- size_t len = strlen(threadname);
- if (len && threadname[len - 1] == '\n') {
- threadname[len - 1] = '\0';
- }
- }
- }
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, const char* process_name,
+ const char* thread_name) {
// Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
- static const char logd[] = "logd";
- if (threadname != nullptr && !strncmp(threadname, logd, sizeof(logd) - 1)
- && (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
+ // TODO: Why is this controlled by thread name?
+ if (strcmp(thread_name, "logd") == 0 || strncmp(thread_name, "logd.", 4) == 0) {
log->should_retrieve_logcat = false;
}
- char procnamebuf[1024];
- char* procname = nullptr;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
- _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
- threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, thread_name,
+ process_name);
}
static void dump_stack_segment(
@@ -493,13 +470,14 @@ static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
}
}
-static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map,
+static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name,
+ const std::string& thread_name, BacktraceMap* map,
uintptr_t abort_msg_address, bool primary_thread) {
log->current_tid = tid;
if (!primary_thread) {
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
}
- dump_thread_info(log, pid, tid);
+ dump_thread_info(log, pid, tid, process_name.c_str(), thread_name.c_str());
dump_signal_info(log, tid);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
@@ -654,9 +632,9 @@ static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
}
// Dumps all information about the specified pid to the tombstone.
-static void dump_crash(log_t* log, BacktraceMap* map,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>* siblings, uintptr_t abort_msg_address) {
+static void dump_crash(log_t* log, BacktraceMap* map, const OpenFilesList* open_files, pid_t pid,
+ pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address) {
// don't copy log messages to tombstone unless this is a dev device
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "0");
@@ -665,14 +643,17 @@ static void dump_crash(log_t* log, BacktraceMap* map,
_LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_header_info(log);
- dump_thread(log, pid, tid, map, abort_msg_address, true);
+ dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true);
if (want_logs) {
dump_logs(log, pid, 5);
}
- if (siblings && !siblings->empty()) {
- for (pid_t sibling : *siblings) {
- dump_thread(log, pid, sibling, map, 0, false);
+ for (const auto& it : threads) {
+ pid_t thread_tid = it.first;
+ const std::string& thread_name = it.second;
+
+ if (thread_tid != tid) {
+ dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false);
}
}
@@ -739,16 +720,16 @@ int open_tombstone(std::string* out_path) {
return fd;
}
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
- const OpenFilesList* open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>* siblings, uintptr_t abort_msg_address,
+void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
+ pid_t pid, pid_t tid, const std::string& process_name,
+ const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
std::string* amfd_data) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
log.tfd = tombstone_fd;
log.amfd_data = amfd_data;
- dump_crash(&log, map, open_files, pid, tid, siblings, abort_msg_address);
+ dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address);
}
void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
@@ -762,7 +743,13 @@ void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, s
log.tfd = tombstone_fd;
log.amfd_data = nullptr;
- dump_thread_info(&log, pid, tid);
+ char thread_name[16];
+ char process_name[128];
+
+ read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
+ read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
+
+ dump_thread_info(&log, pid, tid, thread_name, process_name);
dump_signal_info(&log, siginfo);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 744cd72af..22fde5ea4 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -28,6 +28,7 @@
#include <string>
#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
@@ -202,3 +203,20 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
}
}
+
+void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
+ android::base::unique_fd fd(open(path, O_RDONLY));
+ if (fd != -1) {
+ int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
+ if (rc != -1) {
+ buf[rc] = '\0';
+
+ // Trim trailing newlines.
+ if (rc > 0 && buf[rc - 1] == '\n') {
+ buf[rc - 1] = '\0';
+ }
+ return;
+ }
+ }
+ strcpy(buf, default_value);
+}