OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/crash_handler_host_linux.h" | 5 #include "chrome/browser/crash_handler_host_linux.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
| 10 #include <sys/syscall.h> |
10 #include <sys/types.h> | 11 #include <sys/types.h> |
11 #include <unistd.h> | 12 #include <unistd.h> |
12 | 13 |
13 #include "base/eintr_wrapper.h" | 14 #include "base/eintr_wrapper.h" |
14 #include "base/file_path.h" | 15 #include "base/file_path.h" |
15 #include "base/format_macros.h" | 16 #include "base/format_macros.h" |
16 #include "base/linux_util.h" | 17 #include "base/linux_util.h" |
17 #include "base/logging.h" | 18 #include "base/logging.h" |
18 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
19 #include "base/path_service.h" | 20 #include "base/path_service.h" |
20 #include "base/rand_util.h" | 21 #include "base/rand_util.h" |
21 #include "base/string_util.h" | 22 #include "base/string_util.h" |
22 #include "breakpad/src/client/linux/handler/exception_handler.h" | 23 #include "breakpad/src/client/linux/handler/exception_handler.h" |
23 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" | 24 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" |
24 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" | 25 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" |
25 #include "chrome/app/breakpad_linux.h" | 26 #include "chrome/app/breakpad_linux.h" |
26 #include "chrome/browser/chrome_thread.h" | 27 #include "chrome/browser/chrome_thread.h" |
27 #include "chrome/common/chrome_paths.h" | 28 #include "chrome/common/chrome_paths.h" |
28 #include "chrome/common/env_vars.h" | 29 #include "chrome/common/env_vars.h" |
29 | 30 |
| 31 using google_breakpad::ExceptionHandler; |
| 32 |
30 // Since classes derived from CrashHandlerHostLinux are singletons, it's only | 33 // Since classes derived from CrashHandlerHostLinux are singletons, it's only |
31 // destroyed at the end of the processes lifetime, which is greater in span than | 34 // destroyed at the end of the processes lifetime, which is greater in span than |
32 // the lifetime of the IO message loop. | 35 // the lifetime of the IO message loop. |
33 DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux); | 36 DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux); |
34 | 37 |
35 CrashHandlerHostLinux::CrashHandlerHostLinux() | 38 CrashHandlerHostLinux::CrashHandlerHostLinux() |
36 : process_socket_(-1), | 39 : process_socket_(-1), |
37 browser_socket_(-1) { | 40 browser_socket_(-1) { |
38 int fds[2]; | 41 int fds[2]; |
39 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from | 42 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 // A process has crashed and has signaled us by writing a datagram | 83 // A process has crashed and has signaled us by writing a datagram |
81 // to the death signal socket. The datagram contains the crash context needed | 84 // to the death signal socket. The datagram contains the crash context needed |
82 // for writing the minidump as well as a file descriptor and a credentials | 85 // for writing the minidump as well as a file descriptor and a credentials |
83 // block so that they can't lie about their pid. | 86 // block so that they can't lie about their pid. |
84 | 87 |
85 // The length of the control message: | 88 // The length of the control message: |
86 static const unsigned kControlMsgSize = | 89 static const unsigned kControlMsgSize = |
87 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); | 90 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); |
88 // The length of the regular payload: | 91 // The length of the regular payload: |
89 static const unsigned kCrashContextSize = | 92 static const unsigned kCrashContextSize = |
90 sizeof(google_breakpad::ExceptionHandler::CrashContext); | 93 sizeof(ExceptionHandler::CrashContext); |
91 | 94 |
92 struct msghdr msg = {0}; | 95 struct msghdr msg = {0}; |
93 struct iovec iov[4]; | 96 struct iovec iov[6]; |
94 char crash_context[kCrashContextSize]; | 97 char crash_context[kCrashContextSize]; |
95 char guid[kGuidSize + 1]; | 98 char guid[kGuidSize + 1]; |
96 char crash_url[kMaxActiveURLSize + 1]; | 99 char crash_url[kMaxActiveURLSize + 1]; |
97 char distro[kDistroSize + 1]; | 100 char distro[kDistroSize + 1]; |
| 101 char* tid_buf_addr = NULL; |
| 102 int tid_fd = -1; |
98 char control[kControlMsgSize]; | 103 char control[kControlMsgSize]; |
99 const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) + | 104 const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) + |
100 sizeof(crash_url) + sizeof(distro); | 105 sizeof(crash_url) + sizeof(distro) + |
| 106 sizeof(tid_buf_addr) + sizeof(tid_fd); |
101 | 107 |
102 iov[0].iov_base = crash_context; | 108 iov[0].iov_base = crash_context; |
103 iov[0].iov_len = sizeof(crash_context); | 109 iov[0].iov_len = sizeof(crash_context); |
104 iov[1].iov_base = guid; | 110 iov[1].iov_base = guid; |
105 iov[1].iov_len = sizeof(guid); | 111 iov[1].iov_len = sizeof(guid); |
106 iov[2].iov_base = crash_url; | 112 iov[2].iov_base = crash_url; |
107 iov[2].iov_len = sizeof(crash_url); | 113 iov[2].iov_len = sizeof(crash_url); |
108 iov[3].iov_base = distro; | 114 iov[3].iov_base = distro; |
109 iov[3].iov_len = sizeof(distro); | 115 iov[3].iov_len = sizeof(distro); |
| 116 iov[4].iov_base = &tid_buf_addr; |
| 117 iov[4].iov_len = sizeof(tid_buf_addr); |
| 118 iov[5].iov_base = &tid_fd; |
| 119 iov[5].iov_len = sizeof(tid_fd); |
110 msg.msg_iov = iov; | 120 msg.msg_iov = iov; |
111 msg.msg_iovlen = 4; | 121 msg.msg_iovlen = 6; |
112 msg.msg_control = control; | 122 msg.msg_control = control; |
113 msg.msg_controllen = kControlMsgSize; | 123 msg.msg_controllen = kControlMsgSize; |
114 | 124 |
115 const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0)); | 125 const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0)); |
116 if (msg_size != expected_msg_size) { | 126 if (msg_size != expected_msg_size) { |
117 LOG(ERROR) << "Error reading from death signal socket. Crash dumping" | 127 LOG(ERROR) << "Error reading from death signal socket. Crash dumping" |
118 << " is disabled." | 128 << " is disabled." |
119 << " msg_size:" << msg_size | 129 << " msg_size:" << msg_size |
120 << " errno:" << errno; | 130 << " errno:" << errno; |
121 file_descriptor_watcher_.StopWatchingFileDescriptor(); | 131 file_descriptor_watcher_.StopWatchingFileDescriptor(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 // In the future we can remove this workaround, but we have to wait a couple | 186 // In the future we can remove this workaround, but we have to wait a couple |
177 // of years to be sure that it's worked its way out into the world. | 187 // of years to be sure that it's worked its way out into the world. |
178 | 188 |
179 uint64_t inode_number; | 189 uint64_t inode_number; |
180 if (!base::FileDescriptorGetInode(&inode_number, signal_fd)) { | 190 if (!base::FileDescriptorGetInode(&inode_number, signal_fd)) { |
181 LOG(WARNING) << "Failed to get inode number for passed socket"; | 191 LOG(WARNING) << "Failed to get inode number for passed socket"; |
182 HANDLE_EINTR(close(signal_fd)); | 192 HANDLE_EINTR(close(signal_fd)); |
183 return; | 193 return; |
184 } | 194 } |
185 | 195 |
186 if (!base::FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) { | 196 pid_t actual_crashing_pid = -1; |
| 197 if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number - 1)) { |
187 LOG(WARNING) << "Failed to find process holding other end of crash reply " | 198 LOG(WARNING) << "Failed to find process holding other end of crash reply " |
188 "socket"; | 199 "socket"; |
189 HANDLE_EINTR(close(signal_fd)); | 200 HANDLE_EINTR(close(signal_fd)); |
190 return; | 201 return; |
191 } | 202 } |
| 203 if (actual_crashing_pid != crashing_pid) { |
| 204 crashing_pid = actual_crashing_pid; |
| 205 |
| 206 // The crashing TID set inside the compromised context via sys_gettid() |
| 207 // in ExceptionHandler::HandleSignal is also wrong and needs to be |
| 208 // translated. |
| 209 // |
| 210 // We expect the crashing thread to be in sys_read(), waiting for use to |
| 211 // write to |signal_fd|. Most newer kernels where we have the different pid |
| 212 // namespaces also have /proc/[pid]/syscall, so we can look through |
| 213 // |actual_crashing_pid|'s thread group and find the thread that's in the |
| 214 // read syscall with the right arguments. |
| 215 |
| 216 std::string expected_syscall_data; |
| 217 // /proc/[pid]/syscall is formatted as follows: |
| 218 // syscall_number arg1 ... arg6 sp pc |
| 219 // but we just check syscall_number through arg3. |
| 220 StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ", |
| 221 SYS_read, tid_fd, tid_buf_addr); |
| 222 pid_t crashing_tid = |
| 223 base::FindThreadIDWithSyscall(crashing_pid, expected_syscall_data); |
| 224 if (crashing_tid == -1) { |
| 225 // We didn't find the thread we want. Maybe it didn't reach sys_read() |
| 226 // yet, or the kernel doesn't support /proc/[pid]/syscall or the thread |
| 227 // went away. We'll just take a guess here and assume the crashing |
| 228 // thread is the thread group leader. |
| 229 crashing_tid = crashing_pid; |
| 230 } |
| 231 |
| 232 ExceptionHandler::CrashContext* bad_context = |
| 233 reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context); |
| 234 bad_context->tid = crashing_tid; |
| 235 } |
192 | 236 |
193 bool upload = true; | 237 bool upload = true; |
194 FilePath dumps_path("/tmp"); | 238 FilePath dumps_path("/tmp"); |
195 if (getenv(env_vars::kHeadless)) { | 239 if (getenv(env_vars::kHeadless)) { |
196 upload = false; | 240 upload = false; |
197 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); | 241 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); |
198 } | 242 } |
199 const uint64 rand = base::RandUint64(); | 243 const uint64 rand = base::RandUint64(); |
200 const std::string minidump_filename = | 244 const std::string minidump_filename = |
201 StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", | 245 StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", |
(...skipping 29 matching lines...) Expand all Loading... |
231 info.guid_length = strlen(guid); | 275 info.guid_length = strlen(guid); |
232 info.distro = distro; | 276 info.distro = distro; |
233 info.distro_length = strlen(distro); | 277 info.distro_length = strlen(distro); |
234 info.upload = upload; | 278 info.upload = upload; |
235 HandleCrashDump(info); | 279 HandleCrashDump(info); |
236 } | 280 } |
237 | 281 |
238 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { | 282 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { |
239 file_descriptor_watcher_.StopWatchingFileDescriptor(); | 283 file_descriptor_watcher_.StopWatchingFileDescriptor(); |
240 } | 284 } |
OLD | NEW |