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