Index: chrome/browser/crash_handler_host_linux.cc |
=================================================================== |
--- chrome/browser/crash_handler_host_linux.cc (revision 52555) |
+++ chrome/browser/crash_handler_host_linux.cc (working copy) |
@@ -7,6 +7,7 @@ |
#include <stdint.h> |
#include <stdlib.h> |
#include <sys/socket.h> |
+#include <sys/syscall.h> |
#include <sys/types.h> |
#include <unistd.h> |
@@ -27,6 +28,8 @@ |
#include "chrome/common/chrome_paths.h" |
#include "chrome/common/env_vars.h" |
+using google_breakpad::ExceptionHandler; |
+ |
// Since classes derived from CrashHandlerHostLinux are singletons, it's only |
// destroyed at the end of the processes lifetime, which is greater in span than |
// the lifetime of the IO message loop. |
@@ -87,17 +90,20 @@ |
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); |
// The length of the regular payload: |
static const unsigned kCrashContextSize = |
- sizeof(google_breakpad::ExceptionHandler::CrashContext); |
+ sizeof(ExceptionHandler::CrashContext); |
struct msghdr msg = {0}; |
- struct iovec iov[4]; |
+ struct iovec iov[6]; |
char crash_context[kCrashContextSize]; |
char guid[kGuidSize + 1]; |
char crash_url[kMaxActiveURLSize + 1]; |
char distro[kDistroSize + 1]; |
+ char* tid_buf_addr = NULL; |
+ int tid_fd = -1; |
char control[kControlMsgSize]; |
const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) + |
- sizeof(crash_url) + sizeof(distro); |
+ sizeof(crash_url) + sizeof(distro) + |
+ sizeof(tid_buf_addr) + sizeof(tid_fd); |
iov[0].iov_base = crash_context; |
iov[0].iov_len = sizeof(crash_context); |
@@ -107,8 +113,12 @@ |
iov[2].iov_len = sizeof(crash_url); |
iov[3].iov_base = distro; |
iov[3].iov_len = sizeof(distro); |
+ iov[4].iov_base = &tid_buf_addr; |
+ iov[4].iov_len = sizeof(tid_buf_addr); |
+ iov[5].iov_base = &tid_fd; |
+ iov[5].iov_len = sizeof(tid_fd); |
msg.msg_iov = iov; |
- msg.msg_iovlen = 4; |
+ msg.msg_iovlen = 6; |
msg.msg_control = control; |
msg.msg_controllen = kControlMsgSize; |
@@ -183,13 +193,47 @@ |
return; |
} |
- if (!base::FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) { |
+ pid_t actual_crashing_pid = -1; |
+ if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number - 1)) { |
LOG(WARNING) << "Failed to find process holding other end of crash reply " |
"socket"; |
HANDLE_EINTR(close(signal_fd)); |
return; |
} |
+ if (actual_crashing_pid != crashing_pid) { |
+ crashing_pid = actual_crashing_pid; |
+ // The crashing TID set inside the compromised context via sys_gettid() |
+ // in ExceptionHandler::HandleSignal is also wrong and needs to be |
+ // translated. |
+ // |
+ // We expect the crashing thread to be in sys_read(), waiting for use to |
+ // write to |signal_fd|. Most newer kernels where we have the different pid |
+ // namespaces also have /proc/[pid]/syscall, so we can look through |
+ // |actual_crashing_pid|'s thread group and find the thread that's in the |
+ // read syscall with the right arguments. |
+ |
+ std::string expected_syscall_data; |
+ // /proc/[pid]/syscall is formatted as follows: |
+ // syscall_number arg1 ... arg6 sp pc |
+ // but we just check syscall_number through arg3. |
+ StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ", |
+ SYS_read, tid_fd, tid_buf_addr); |
+ pid_t crashing_tid = |
+ base::FindThreadIDWithSyscall(crashing_pid, expected_syscall_data); |
+ if (crashing_tid == -1) { |
+ // We didn't find the thread we want. Maybe it didn't reach sys_read() |
+ // yet, or the kernel doesn't support /proc/[pid]/syscall or the thread |
+ // went away. We'll just take a guess here and assume the crashing |
+ // thread is the thread group leader. |
+ crashing_tid = crashing_pid; |
+ } |
+ |
+ ExceptionHandler::CrashContext* bad_context = |
+ reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context); |
+ bad_context->tid = crashing_tid; |
+ } |
+ |
bool upload = true; |
FilePath dumps_path("/tmp"); |
if (getenv(env_vars::kHeadless)) { |