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/syscall.h> |
11 #include <sys/types.h> | 11 #include <sys/types.h> |
12 #include <unistd.h> | 12 #include <unistd.h> |
13 | 13 |
14 #include "base/eintr_wrapper.h" | 14 #include "base/eintr_wrapper.h" |
15 #include "base/file_path.h" | 15 #include "base/file_path.h" |
16 #include "base/format_macros.h" | 16 #include "base/format_macros.h" |
17 #include "base/linux_util.h" | 17 #include "base/linux_util.h" |
18 #include "base/logging.h" | 18 #include "base/logging.h" |
19 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
20 #include "base/path_service.h" | 20 #include "base/path_service.h" |
21 #include "base/rand_util.h" | 21 #include "base/rand_util.h" |
22 #include "base/string_util.h" | 22 #include "base/string_util.h" |
| 23 #include "base/task.h" |
| 24 #include "base/thread.h" |
23 #include "breakpad/src/client/linux/handler/exception_handler.h" | 25 #include "breakpad/src/client/linux/handler/exception_handler.h" |
24 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" | 26 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" |
25 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" | 27 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" |
26 #include "chrome/app/breakpad_linux.h" | 28 #include "chrome/app/breakpad_linux.h" |
27 #include "chrome/browser/chrome_thread.h" | 29 #include "chrome/browser/chrome_thread.h" |
28 #include "chrome/common/chrome_paths.h" | 30 #include "chrome/common/chrome_paths.h" |
29 #include "chrome/common/env_vars.h" | 31 #include "chrome/common/env_vars.h" |
30 | 32 |
31 using google_breakpad::ExceptionHandler; | 33 using google_breakpad::ExceptionHandler; |
32 | 34 |
| 35 namespace { |
| 36 |
| 37 // Handles the crash dump and frees the allocated BreakpadInfo struct. |
| 38 void CrashDumpTask(BreakpadInfo* info) { |
| 39 HandleCrashDump(*info); |
| 40 delete[] info->filename; |
| 41 delete[] info->process_type; |
| 42 delete[] info->crash_url; |
| 43 delete[] info->guid; |
| 44 delete[] info->distro; |
| 45 delete info; |
| 46 } |
| 47 |
| 48 } // namespace |
| 49 |
33 // Since classes derived from CrashHandlerHostLinux are singletons, it's only | 50 // Since classes derived from CrashHandlerHostLinux are singletons, it's only |
34 // destroyed at the end of the processes lifetime, which is greater in span than | 51 // destroyed at the end of the processes lifetime, which is greater in span than |
35 // the lifetime of the IO message loop. | 52 // the lifetime of the IO message loop. |
36 DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux); | 53 DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux); |
37 | 54 |
38 CrashHandlerHostLinux::CrashHandlerHostLinux() | 55 CrashHandlerHostLinux::CrashHandlerHostLinux() { |
39 : process_socket_(-1), | |
40 browser_socket_(-1) { | |
41 int fds[2]; | 56 int fds[2]; |
42 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from | 57 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from |
43 // sending datagrams to other sockets on the system. The sandbox may prevent | 58 // sending datagrams to other sockets on the system. The sandbox may prevent |
44 // the process from calling socket() to create new sockets, but it'll still | 59 // the process from calling socket() to create new sockets, but it'll still |
45 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send | 60 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send |
46 // a datagram to any (abstract) socket on the same system. With | 61 // a datagram to any (abstract) socket on the same system. With |
47 // SOCK_SEQPACKET, this is prevented. | 62 // SOCK_SEQPACKET, this is prevented. |
48 CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0); | 63 CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0); |
49 static const int on = 1; | 64 static const int on = 1; |
50 | 65 |
51 // Enable passcred on the server end of the socket | 66 // Enable passcred on the server end of the socket |
52 CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0); | 67 CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0); |
53 | 68 |
54 process_socket_ = fds[0]; | 69 process_socket_ = fds[0]; |
55 browser_socket_ = fds[1]; | 70 browser_socket_ = fds[1]; |
56 | 71 |
57 ChromeThread::PostTask( | 72 ChromeThread::PostTask( |
58 ChromeThread::IO, FROM_HERE, | 73 ChromeThread::IO, FROM_HERE, |
59 NewRunnableMethod(this, &CrashHandlerHostLinux::Init)); | 74 NewRunnableMethod(this, &CrashHandlerHostLinux::Init)); |
60 } | 75 } |
61 | 76 |
62 CrashHandlerHostLinux::~CrashHandlerHostLinux() { | 77 CrashHandlerHostLinux::~CrashHandlerHostLinux() { |
63 HANDLE_EINTR(close(process_socket_)); | 78 HANDLE_EINTR(close(process_socket_)); |
64 HANDLE_EINTR(close(browser_socket_)); | 79 HANDLE_EINTR(close(browser_socket_)); |
| 80 |
| 81 // If we are quitting and there are crash dumps in the queue, discard them. |
| 82 uploader_thread_->message_loop()->QuitNow(); |
65 } | 83 } |
66 | 84 |
67 void CrashHandlerHostLinux::Init() { | 85 void CrashHandlerHostLinux::Init() { |
| 86 SetProcessType(); |
| 87 uploader_thread_.reset( |
| 88 new base::Thread(std::string(process_type_ + "_crash_uploader").c_str())); |
| 89 uploader_thread_->Start(); |
| 90 |
68 MessageLoopForIO* ml = MessageLoopForIO::current(); | 91 MessageLoopForIO* ml = MessageLoopForIO::current(); |
69 CHECK(ml->WatchFileDescriptor( | 92 CHECK(ml->WatchFileDescriptor( |
70 browser_socket_, true /* persistent */, | 93 browser_socket_, true /* persistent */, |
71 MessageLoopForIO::WATCH_READ, | 94 MessageLoopForIO::WATCH_READ, |
72 &file_descriptor_watcher_, this)); | 95 &file_descriptor_watcher_, this)); |
73 ml->AddDestructionObserver(this); | 96 ml->AddDestructionObserver(this); |
74 } | 97 } |
75 | 98 |
76 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) { | 99 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) { |
77 DCHECK(false); | 100 DCHECK(false); |
(...skipping 10 matching lines...) Expand all Loading... |
88 // The length of the control message: | 111 // The length of the control message: |
89 static const unsigned kControlMsgSize = | 112 static const unsigned kControlMsgSize = |
90 CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); | 113 CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); |
91 // The length of the regular payload: | 114 // The length of the regular payload: |
92 static const unsigned kCrashContextSize = | 115 static const unsigned kCrashContextSize = |
93 sizeof(ExceptionHandler::CrashContext); | 116 sizeof(ExceptionHandler::CrashContext); |
94 | 117 |
95 struct msghdr msg = {0}; | 118 struct msghdr msg = {0}; |
96 struct iovec iov[6]; | 119 struct iovec iov[6]; |
97 char crash_context[kCrashContextSize]; | 120 char crash_context[kCrashContextSize]; |
98 char guid[kGuidSize + 1]; | 121 char* guid = new char[kGuidSize + 1]; |
99 char crash_url[kMaxActiveURLSize + 1]; | 122 char* crash_url = new char[kMaxActiveURLSize + 1]; |
100 char distro[kDistroSize + 1]; | 123 char* distro = new char[kDistroSize + 1]; |
101 char* tid_buf_addr = NULL; | 124 char* tid_buf_addr = NULL; |
102 int tid_fd = -1; | 125 int tid_fd = -1; |
103 char control[kControlMsgSize]; | 126 char control[kControlMsgSize]; |
104 const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) + | 127 const ssize_t expected_msg_size = sizeof(crash_context) + |
105 sizeof(crash_url) + sizeof(distro) + | 128 kGuidSize + 1 + |
| 129 kMaxActiveURLSize + 1 + |
| 130 kDistroSize + 1 + |
106 sizeof(tid_buf_addr) + sizeof(tid_fd); | 131 sizeof(tid_buf_addr) + sizeof(tid_fd); |
107 | 132 |
108 iov[0].iov_base = crash_context; | 133 iov[0].iov_base = crash_context; |
109 iov[0].iov_len = sizeof(crash_context); | 134 iov[0].iov_len = sizeof(crash_context); |
110 iov[1].iov_base = guid; | 135 iov[1].iov_base = guid; |
111 iov[1].iov_len = sizeof(guid); | 136 iov[1].iov_len = kGuidSize + 1; |
112 iov[2].iov_base = crash_url; | 137 iov[2].iov_base = crash_url; |
113 iov[2].iov_len = sizeof(crash_url); | 138 iov[2].iov_len = kMaxActiveURLSize + 1; |
114 iov[3].iov_base = distro; | 139 iov[3].iov_base = distro; |
115 iov[3].iov_len = sizeof(distro); | 140 iov[3].iov_len = kDistroSize + 1; |
116 iov[4].iov_base = &tid_buf_addr; | 141 iov[4].iov_base = &tid_buf_addr; |
117 iov[4].iov_len = sizeof(tid_buf_addr); | 142 iov[4].iov_len = sizeof(tid_buf_addr); |
118 iov[5].iov_base = &tid_fd; | 143 iov[5].iov_base = &tid_fd; |
119 iov[5].iov_len = sizeof(tid_fd); | 144 iov[5].iov_len = sizeof(tid_fd); |
120 msg.msg_iov = iov; | 145 msg.msg_iov = iov; |
121 msg.msg_iovlen = 6; | 146 msg.msg_iovlen = 6; |
122 msg.msg_control = control; | 147 msg.msg_control = control; |
123 msg.msg_controllen = kControlMsgSize; | 148 msg.msg_controllen = kControlMsgSize; |
124 | 149 |
125 const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0)); | 150 const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0)); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 crashing_tid = crashing_pid; | 265 crashing_tid = crashing_pid; |
241 } | 266 } |
242 | 267 |
243 ExceptionHandler::CrashContext* bad_context = | 268 ExceptionHandler::CrashContext* bad_context = |
244 reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context); | 269 reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context); |
245 bad_context->tid = crashing_tid; | 270 bad_context->tid = crashing_tid; |
246 } | 271 } |
247 | 272 |
248 bool upload = true; | 273 bool upload = true; |
249 FilePath dumps_path("/tmp"); | 274 FilePath dumps_path("/tmp"); |
| 275 PathService::Get(base::DIR_TEMP, &dumps_path); |
250 if (getenv(env_vars::kHeadless)) { | 276 if (getenv(env_vars::kHeadless)) { |
251 upload = false; | 277 upload = false; |
252 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); | 278 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); |
253 } | 279 } |
254 const uint64 rand = base::RandUint64(); | 280 const uint64 rand = base::RandUint64(); |
255 const std::string minidump_filename = | 281 const std::string minidump_filename = |
256 StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", | 282 StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", |
257 dumps_path.value().c_str(), process_type_.c_str(), rand); | 283 dumps_path.value().c_str(), process_type_.c_str(), rand); |
258 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), | 284 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), |
259 crashing_pid, crash_context, | 285 crashing_pid, crash_context, |
260 kCrashContextSize)) { | 286 kCrashContextSize)) { |
261 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid; | 287 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid; |
262 HANDLE_EINTR(close(signal_fd)); | 288 HANDLE_EINTR(close(signal_fd)); |
263 } | 289 } |
264 | 290 |
265 // Send the done signal to the process: it can exit now. | 291 // Send the done signal to the process: it can exit now. |
266 memset(&msg, 0, sizeof(msg)); | 292 memset(&msg, 0, sizeof(msg)); |
267 struct iovec done_iov; | 293 struct iovec done_iov; |
268 done_iov.iov_base = const_cast<char*>("\x42"); | 294 done_iov.iov_base = const_cast<char*>("\x42"); |
269 done_iov.iov_len = 1; | 295 done_iov.iov_len = 1; |
270 msg.msg_iov = &done_iov; | 296 msg.msg_iov = &done_iov; |
271 msg.msg_iovlen = 1; | 297 msg.msg_iovlen = 1; |
272 | 298 |
273 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); | 299 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); |
274 HANDLE_EINTR(close(signal_fd)); | 300 HANDLE_EINTR(close(signal_fd)); |
275 | 301 |
276 // Sanitize the string data a bit more | 302 // Sanitize the string data a bit more |
277 guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0; | 303 guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0; |
278 | 304 |
279 BreakpadInfo info; | 305 BreakpadInfo* info = new BreakpadInfo; |
280 info.filename = minidump_filename.c_str(); | 306 |
281 info.process_type = process_type_.c_str(); | 307 char* minidump_filename_str = new char[minidump_filename.length() + 1]; |
282 info.process_type_length = process_type_.length(); | 308 minidump_filename.copy(minidump_filename_str, minidump_filename.length()); |
283 info.crash_url = crash_url; | 309 minidump_filename_str[minidump_filename.length()] = '\0'; |
284 info.crash_url_length = strlen(crash_url); | 310 info->filename = minidump_filename_str; |
285 info.guid = guid; | 311 |
286 info.guid_length = strlen(guid); | 312 info->process_type_length = process_type_.length(); |
287 info.distro = distro; | 313 char* process_type_str = new char[info->process_type_length + 1]; |
288 info.distro_length = strlen(distro); | 314 process_type_.copy(process_type_str, info->process_type_length); |
289 info.upload = upload; | 315 process_type_str[info->process_type_length] = '\0'; |
290 HandleCrashDump(info); | 316 info->process_type = process_type_str; |
| 317 |
| 318 info->crash_url_length = strlen(crash_url); |
| 319 info->crash_url = crash_url; |
| 320 |
| 321 info->guid_length = strlen(guid); |
| 322 info->guid = guid; |
| 323 |
| 324 info->distro_length = strlen(distro); |
| 325 info->distro = distro; |
| 326 |
| 327 info->upload = upload; |
| 328 |
| 329 uploader_thread_->message_loop()->PostTask( |
| 330 FROM_HERE, |
| 331 NewRunnableFunction(&CrashDumpTask, info)); |
291 } | 332 } |
292 | 333 |
293 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { | 334 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { |
294 file_descriptor_watcher_.StopWatchingFileDescriptor(); | 335 file_descriptor_watcher_.StopWatchingFileDescriptor(); |
295 } | 336 } |
| 337 |
| 338 PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() { |
| 339 } |
| 340 |
| 341 PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() { |
| 342 } |
| 343 |
| 344 void PluginCrashHandlerHostLinux::SetProcessType() { |
| 345 process_type_ = "plugin"; |
| 346 } |
| 347 |
| 348 RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() { |
| 349 } |
| 350 |
| 351 RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() { |
| 352 } |
| 353 |
| 354 void RendererCrashHandlerHostLinux::SetProcessType() { |
| 355 process_type_ = "renderer"; |
| 356 } |
OLD | NEW |