- add sources.
[platform/framework/web/crosswalk.git] / src / components / breakpad / browser / crash_handler_host_linux.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/breakpad/browser/crash_handler_host_linux.h"
6
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <sys/socket.h>
10 #include <sys/syscall.h>
11 #include <unistd.h>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/files/file_path.h"
16 #include "base/format_macros.h"
17 #include "base/linux_util.h"
18 #include "base/logging.h"
19 #include "base/memory/singleton.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/path_service.h"
22 #include "base/posix/eintr_wrapper.h"
23 #include "base/rand_util.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/threading/thread.h"
27 #include "breakpad/src/client/linux/handler/exception_handler.h"
28 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
29 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
30 #include "components/breakpad/app/breakpad_linux_impl.h"
31 #include "content/public/browser/browser_thread.h"
32
33 #if defined(OS_ANDROID)
34 #include <sys/linux-syscalls.h>
35
36 #define SYS_read __NR_read
37 #endif
38
39 using content::BrowserThread;
40 using google_breakpad::ExceptionHandler;
41
42 namespace breakpad {
43
44 namespace {
45
46 // The length of the control message:
47 const unsigned kControlMsgSize =
48     CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
49 // The length of the regular payload:
50 const unsigned kCrashContextSize = sizeof(ExceptionHandler::CrashContext);
51
52 // Handles the crash dump and frees the allocated BreakpadInfo struct.
53 void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) {
54   if (handler->IsShuttingDown())
55     return;
56
57   HandleCrashDump(*info);
58   delete[] info->filename;
59   delete[] info->process_type;
60   delete[] info->distro;
61   delete info->crash_keys;
62   delete info;
63 }
64
65 }  // namespace
66
67 // Since instances of CrashHandlerHostLinux are leaked, they are only destroyed
68 // at the end of the processes lifetime, which is greater in span than the
69 // lifetime of the IO message loop. Thus, all calls to base::Bind() use
70 // non-refcounted pointers.
71
72 CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type,
73                                              const base::FilePath& dumps_path,
74                                              bool upload)
75     : process_type_(process_type),
76       dumps_path_(dumps_path),
77       upload_(upload),
78       shutting_down_(false),
79       worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()) {
80   int fds[2];
81   // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
82   // sending datagrams to other sockets on the system. The sandbox may prevent
83   // the process from calling socket() to create new sockets, but it'll still
84   // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send
85   // a datagram to any (abstract) socket on the same system. With
86   // SOCK_SEQPACKET, this is prevented.
87   CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0);
88   static const int on = 1;
89
90   // Enable passcred on the server end of the socket
91   CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0);
92
93   process_socket_ = fds[0];
94   browser_socket_ = fds[1];
95
96   BrowserThread::PostTask(
97       BrowserThread::IO, FROM_HERE,
98       base::Bind(&CrashHandlerHostLinux::Init, base::Unretained(this)));
99 }
100
101 CrashHandlerHostLinux::~CrashHandlerHostLinux() {
102   (void) HANDLE_EINTR(close(process_socket_));
103   (void) HANDLE_EINTR(close(browser_socket_));
104 }
105
106 void CrashHandlerHostLinux::StartUploaderThread() {
107   uploader_thread_.reset(
108       new base::Thread(std::string(process_type_ + "_crash_uploader").c_str()));
109   uploader_thread_->Start();
110 }
111
112 void CrashHandlerHostLinux::Init() {
113   base::MessageLoopForIO* ml = base::MessageLoopForIO::current();
114   CHECK(ml->WatchFileDescriptor(
115       browser_socket_, true /* persistent */,
116       base::MessageLoopForIO::WATCH_READ,
117       &file_descriptor_watcher_, this));
118   ml->AddDestructionObserver(this);
119 }
120
121 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) {
122   NOTREACHED();
123 }
124
125 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
126   DCHECK_EQ(fd, browser_socket_);
127
128   // A process has crashed and has signaled us by writing a datagram
129   // to the death signal socket. The datagram contains the crash context needed
130   // for writing the minidump as well as a file descriptor and a credentials
131   // block so that they can't lie about their pid.
132   //
133   // The message sender is in components/breakpad/app/breakpad_linux.cc.
134
135   struct msghdr msg = {0};
136   struct iovec iov[kCrashIovSize];
137
138   // Freed in WriteDumpFile();
139   char* crash_context = new char[kCrashContextSize];
140   // Freed in CrashDumpTask();
141   char* distro = new char[kDistroSize + 1];
142 #if defined(ADDRESS_SANITIZER)
143   asan_report_str_ = new char[kMaxAsanReportSize + 1];
144 #endif
145
146   // Freed in CrashDumpTask().
147   CrashKeyStorage* crash_keys = new CrashKeyStorage;
148   google_breakpad::SerializedNonAllocatingMap* serialized_crash_keys;
149   size_t crash_keys_size = crash_keys->Serialize(
150       const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
151           &serialized_crash_keys));
152
153   char* tid_buf_addr = NULL;
154   int tid_fd = -1;
155   uint64_t uptime;
156   size_t oom_size;
157   char control[kControlMsgSize];
158   const ssize_t expected_msg_size =
159       kCrashContextSize +
160       kDistroSize + 1 +
161       sizeof(tid_buf_addr) + sizeof(tid_fd) +
162       sizeof(uptime) +
163 #if defined(ADDRESS_SANITIZER)
164       kMaxAsanReportSize + 1 +
165 #endif
166       sizeof(oom_size) +
167       crash_keys_size;
168   iov[0].iov_base = crash_context;
169   iov[0].iov_len = kCrashContextSize;
170   iov[1].iov_base = distro;
171   iov[1].iov_len = kDistroSize + 1;
172   iov[2].iov_base = &tid_buf_addr;
173   iov[2].iov_len = sizeof(tid_buf_addr);
174   iov[3].iov_base = &tid_fd;
175   iov[3].iov_len = sizeof(tid_fd);
176   iov[4].iov_base = &uptime;
177   iov[4].iov_len = sizeof(uptime);
178   iov[5].iov_base = &oom_size;
179   iov[5].iov_len = sizeof(oom_size);
180   iov[6].iov_base = serialized_crash_keys;
181   iov[6].iov_len = crash_keys_size;
182 #if defined(ADDRESS_SANITIZER)
183   iov[7].iov_base = asan_report_str_;
184   iov[7].iov_len = kMaxAsanReportSize + 1;
185 #endif
186   msg.msg_iov = iov;
187   msg.msg_iovlen = kCrashIovSize;
188   msg.msg_control = control;
189   msg.msg_controllen = kControlMsgSize;
190
191   const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0));
192   if (msg_size != expected_msg_size) {
193     LOG(ERROR) << "Error reading from death signal socket. Crash dumping"
194                << " is disabled."
195                << " msg_size:" << msg_size
196                << " errno:" << errno;
197     file_descriptor_watcher_.StopWatchingFileDescriptor();
198     return;
199   }
200
201   if (msg.msg_controllen != kControlMsgSize ||
202       msg.msg_flags & ~MSG_TRUNC) {
203     LOG(ERROR) << "Received death signal message with the wrong size;"
204                << " msg.msg_controllen:" << msg.msg_controllen
205                << " msg.msg_flags:" << msg.msg_flags
206                << " kCrashContextSize:" << kCrashContextSize
207                << " kControlMsgSize:" << kControlMsgSize;
208     return;
209   }
210
211   // Walk the control payload an extract the file descriptor and validated pid.
212   pid_t crashing_pid = -1;
213   int partner_fd = -1;
214   int signal_fd = -1;
215   for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
216        hdr = CMSG_NXTHDR(&msg, hdr)) {
217     if (hdr->cmsg_level != SOL_SOCKET)
218       continue;
219     if (hdr->cmsg_type == SCM_RIGHTS) {
220       const unsigned len = hdr->cmsg_len -
221           (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
222       DCHECK_EQ(len % sizeof(int), 0u);
223       const unsigned num_fds = len / sizeof(int);
224       if (num_fds != 2) {
225         // A nasty process could try and send us too many descriptors and
226         // force a leak.
227         LOG(ERROR) << "Death signal contained wrong number of descriptors;"
228                    << " num_fds:" << num_fds;
229         for (unsigned i = 0; i < num_fds; ++i)
230           (void) HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
231         return;
232       } else {
233         partner_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
234         signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[1];
235       }
236     } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
237       const struct ucred *cred =
238           reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
239       crashing_pid = cred->pid;
240     }
241   }
242
243   if (crashing_pid == -1 || partner_fd == -1 || signal_fd == -1) {
244     LOG(ERROR) << "Death signal message didn't contain all expected control"
245                << " messages";
246     if (partner_fd >= 0)
247       (void) HANDLE_EINTR(close(partner_fd));
248     if (signal_fd >= 0)
249       (void) HANDLE_EINTR(close(signal_fd));
250     return;
251   }
252
253   // Kernel bug workaround (broken in 2.6.30 and 2.6.32, working in 2.6.38).
254   // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
255   // namespaces. Thus |crashing_pid| might be garbage from our point of view.
256   // In the future we can remove this workaround, but we have to wait a couple
257   // of years to be sure that it's worked its way out into the world.
258   // TODO(thestig) Remove the workaround when Ubuntu Lucid is deprecated.
259
260   // The crashing process closes its copy of the signal_fd immediately after
261   // calling sendmsg(). We can thus not reliably look for with with
262   // FindProcessHoldingSocket(). But by necessity, it has to keep the
263   // partner_fd open until the crashdump is complete.
264   ino_t inode_number;
265   if (!base::FileDescriptorGetInode(&inode_number, partner_fd)) {
266     LOG(WARNING) << "Failed to get inode number for passed socket";
267     (void) HANDLE_EINTR(close(partner_fd));
268     (void) HANDLE_EINTR(close(signal_fd));
269     return;
270   }
271   (void) HANDLE_EINTR(close(partner_fd));
272
273   pid_t actual_crashing_pid = -1;
274   if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number)) {
275     LOG(WARNING) << "Failed to find process holding other end of crash reply "
276                     "socket";
277     (void) HANDLE_EINTR(close(signal_fd));
278     return;
279   }
280
281   crashing_pid = actual_crashing_pid;
282
283   // The crashing TID set inside the compromised context via
284   // sys_gettid() in ExceptionHandler::HandleSignal might be wrong (if
285   // the kernel supports PID namespacing) and may need to be
286   // translated.
287   //
288   // We expect the crashing thread to be in sys_read(), waiting for us to
289   // write to |signal_fd|. Most newer kernels where we have the different pid
290   // namespaces also have /proc/[pid]/syscall, so we can look through
291   // |actual_crashing_pid|'s thread group and find the thread that's in the
292   // read syscall with the right arguments.
293
294   std::string expected_syscall_data;
295   // /proc/[pid]/syscall is formatted as follows:
296   // syscall_number arg1 ... arg6 sp pc
297   // but we just check syscall_number through arg3.
298   base::StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
299                       SYS_read, tid_fd, tid_buf_addr);
300   bool syscall_supported = false;
301   pid_t crashing_tid =
302       base::FindThreadIDWithSyscall(crashing_pid,
303                                     expected_syscall_data,
304                                     &syscall_supported);
305   if (crashing_tid == -1) {
306     // We didn't find the thread we want. Maybe it didn't reach
307     // sys_read() yet or the thread went away.  We'll just take a
308     // guess here and assume the crashing thread is the thread group
309     // leader.  If procfs syscall is not supported by the kernel, then
310     // we assume the kernel also does not support TID namespacing and
311     // trust the TID passed by the crashing process.
312     LOG(WARNING) << "Could not translate tid - assuming crashing thread is "
313         "thread group leader; syscall_supported=" << syscall_supported;
314     crashing_tid = crashing_pid;
315   }
316
317   ExceptionHandler::CrashContext* bad_context =
318       reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
319   bad_context->tid = crashing_tid;
320
321   // Freed in CrashDumpTask();
322   BreakpadInfo* info = new BreakpadInfo;
323
324   info->fd = -1;
325   info->process_type_length = process_type_.length();
326   char* process_type_str = new char[info->process_type_length + 1];
327   process_type_.copy(process_type_str, info->process_type_length);
328   process_type_str[info->process_type_length] = '\0';
329   info->process_type = process_type_str;
330
331   info->distro_length = strlen(distro);
332   info->distro = distro;
333 #if defined(OS_ANDROID)
334   // Nothing gets uploaded in android.
335   info->upload = false;
336 #else
337   info->upload = upload_;
338 #endif
339
340   info->crash_keys = crash_keys;
341
342 #if defined(ADDRESS_SANITIZER)
343   info->asan_report_str = asan_report_str_;
344   info->asan_report_length = strlen(asan_report_str_);
345 #endif
346   info->process_start_time = uptime;
347   info->oom_size = oom_size;
348
349   BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
350       worker_pool_token_,
351       FROM_HERE,
352       base::Bind(&CrashHandlerHostLinux::WriteDumpFile,
353                  base::Unretained(this),
354                  info,
355                  crashing_pid,
356                  crash_context,
357                  signal_fd));
358 }
359
360 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
361                                           pid_t crashing_pid,
362                                           char* crash_context,
363                                           int signal_fd) {
364   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
365       worker_pool_token_));
366
367   base::FilePath dumps_path("/tmp");
368   PathService::Get(base::DIR_TEMP, &dumps_path);
369   if (!info->upload)
370     dumps_path = dumps_path_;
371   const uint64 rand = base::RandUint64();
372   const std::string minidump_filename =
373       base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp",
374                          dumps_path.value().c_str(),
375                          process_type_.c_str(),
376                          rand);
377
378   if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
379                                       kMaxMinidumpFileSize,
380                                       crashing_pid, crash_context,
381                                       kCrashContextSize,
382                                       google_breakpad::MappingList(),
383                                       google_breakpad::AppMemoryList())) {
384     LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
385   }
386 #if defined(ADDRESS_SANITIZER)
387   // Create a temporary file holding the AddressSanitizer report.
388   const std::string log_filename =
389       base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".log",
390                          dumps_path.value().c_str(),
391                          process_type_.c_str(),
392                          rand);
393   FILE* logfile = fopen(log_filename.c_str(), "w");
394   CHECK(logfile);
395   fprintf(logfile, "%s", asan_report_str_);
396   fclose(logfile);
397 #endif
398
399   delete[] crash_context;
400
401   // Freed in CrashDumpTask();
402   char* minidump_filename_str = new char[minidump_filename.length() + 1];
403   minidump_filename.copy(minidump_filename_str, minidump_filename.length());
404   minidump_filename_str[minidump_filename.length()] = '\0';
405   info->filename = minidump_filename_str;
406 #if defined(ADDRESS_SANITIZER)
407   char* minidump_log_filename_str = new char[minidump_filename.length() + 1];
408   minidump_filename.copy(minidump_log_filename_str, minidump_filename.length());
409   memcpy(minidump_log_filename_str + minidump_filename.length() - 3, "log", 3);
410   minidump_log_filename_str[minidump_filename.length()] = '\0';
411   info->log_filename = minidump_log_filename_str;
412 #endif
413   info->pid = crashing_pid;
414
415   BrowserThread::PostTask(
416       BrowserThread::IO, FROM_HERE,
417       base::Bind(&CrashHandlerHostLinux::QueueCrashDumpTask,
418                  base::Unretained(this),
419                  info,
420                  signal_fd));
421 }
422
423 void CrashHandlerHostLinux::QueueCrashDumpTask(BreakpadInfo* info,
424                                                int signal_fd) {
425   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
426
427   // Send the done signal to the process: it can exit now.
428   struct msghdr msg = {0};
429   struct iovec done_iov;
430   done_iov.iov_base = const_cast<char*>("\x42");
431   done_iov.iov_len = 1;
432   msg.msg_iov = &done_iov;
433   msg.msg_iovlen = 1;
434
435   (void) HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
436   (void) HANDLE_EINTR(close(signal_fd));
437
438   uploader_thread_->message_loop()->PostTask(
439       FROM_HERE,
440       base::Bind(&CrashDumpTask, base::Unretained(this), info));
441 }
442
443 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
444   file_descriptor_watcher_.StopWatchingFileDescriptor();
445
446   // If we are quitting and there are crash dumps in the queue, turn them into
447   // no-ops.
448   shutting_down_ = true;
449   uploader_thread_->Stop();
450 }
451
452 bool CrashHandlerHostLinux::IsShuttingDown() const {
453   return shutting_down_;
454 }
455
456 }  // namespace breakpad