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