Home | History | Annotate | Download | only in crash_generation
      1 // Copyright (c) 2010 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #include <assert.h>
     31 #include <dirent.h>
     32 #include <fcntl.h>
     33 #include <limits.h>
     34 #include <poll.h>
     35 #include <stdio.h>
     36 #include <string.h>
     37 #include <sys/socket.h>
     38 #include <sys/stat.h>
     39 #include <sys/types.h>
     40 #include <unistd.h>
     41 
     42 #include <vector>
     43 
     44 #include "client/linux/crash_generation/crash_generation_server.h"
     45 #include "client/linux/crash_generation/client_info.h"
     46 #include "client/linux/handler/exception_handler.h"
     47 #include "client/linux/minidump_writer/minidump_writer.h"
     48 #include "common/linux/eintr_wrapper.h"
     49 #include "common/linux/guid_creator.h"
     50 #include "common/linux/safe_readlink.h"
     51 
     52 static const char kCommandQuit = 'x';
     53 
     54 namespace google_breakpad {
     55 
     56 CrashGenerationServer::CrashGenerationServer(
     57   const int listen_fd,
     58   OnClientDumpRequestCallback dump_callback,
     59   void* dump_context,
     60   OnClientExitingCallback exit_callback,
     61   void* exit_context,
     62   bool generate_dumps,
     63   const string* dump_path) :
     64     server_fd_(listen_fd),
     65     dump_callback_(dump_callback),
     66     dump_context_(dump_context),
     67     exit_callback_(exit_callback),
     68     exit_context_(exit_context),
     69     generate_dumps_(generate_dumps),
     70     started_(false)
     71 {
     72   if (dump_path)
     73     dump_dir_ = *dump_path;
     74   else
     75     dump_dir_ = "/tmp";
     76 }
     77 
     78 CrashGenerationServer::~CrashGenerationServer()
     79 {
     80   if (started_)
     81     Stop();
     82 }
     83 
     84 bool
     85 CrashGenerationServer::Start()
     86 {
     87   if (started_ || 0 > server_fd_)
     88     return false;
     89 
     90   int control_pipe[2];
     91   if (pipe(control_pipe))
     92     return false;
     93 
     94   if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC))
     95     return false;
     96   if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC))
     97     return false;
     98 
     99   if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK))
    100     return false;
    101 
    102   control_pipe_in_ = control_pipe[0];
    103   control_pipe_out_ = control_pipe[1];
    104 
    105   if (pthread_create(&thread_, NULL,
    106                      ThreadMain, reinterpret_cast<void*>(this)))
    107     return false;
    108 
    109   started_ = true;
    110   return true;
    111 }
    112 
    113 void
    114 CrashGenerationServer::Stop()
    115 {
    116   assert(pthread_self() != thread_);
    117 
    118   if (!started_)
    119     return;
    120 
    121   HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1));
    122 
    123   void* dummy;
    124   pthread_join(thread_, &dummy);
    125 
    126   started_ = false;
    127 }
    128 
    129 //static
    130 bool
    131 CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
    132 {
    133   int fds[2];
    134 
    135   if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds))
    136     return false;
    137 
    138   static const int on = 1;
    139   // Enable passcred on the server end of the socket
    140   if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)))
    141     return false;
    142 
    143   if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
    144     return false;
    145   if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
    146     return false;
    147 
    148   *client_fd = fds[0];
    149   *server_fd = fds[1];
    150   return true;
    151 }
    152 
    153 // The following methods/functions execute on the server thread
    154 
    155 void
    156 CrashGenerationServer::Run()
    157 {
    158   struct pollfd pollfds[2];
    159   memset(&pollfds, 0, sizeof(pollfds));
    160 
    161   pollfds[0].fd = server_fd_;
    162   pollfds[0].events = POLLIN;
    163 
    164   pollfds[1].fd = control_pipe_in_;
    165   pollfds[1].events = POLLIN;
    166 
    167   while (true) {
    168     // infinite timeout
    169     int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
    170     if (-1 == nevents) {
    171       if (EINTR == errno) {
    172         continue;
    173       } else {
    174         return;
    175       }
    176     }
    177 
    178     if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
    179       return;
    180 
    181     if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
    182       return;
    183   }
    184 }
    185 
    186 bool
    187 CrashGenerationServer::ClientEvent(short revents)
    188 {
    189   if (POLLHUP & revents)
    190     return false;
    191   assert(POLLIN & revents);
    192 
    193   // A process has crashed and has signaled us by writing a datagram
    194   // to the death signal socket. The datagram contains the crash context needed
    195   // for writing the minidump as well as a file descriptor and a credentials
    196   // block so that they can't lie about their pid.
    197 
    198   // The length of the control message:
    199   static const unsigned kControlMsgSize =
    200       CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
    201   // The length of the regular payload:
    202   static const unsigned kCrashContextSize =
    203       sizeof(google_breakpad::ExceptionHandler::CrashContext);
    204 
    205   struct msghdr msg = {0};
    206   struct iovec iov[1];
    207   char crash_context[kCrashContextSize];
    208   char control[kControlMsgSize];
    209   const ssize_t expected_msg_size = sizeof(crash_context);
    210 
    211   iov[0].iov_base = crash_context;
    212   iov[0].iov_len = sizeof(crash_context);
    213   msg.msg_iov = iov;
    214   msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
    215   msg.msg_control = control;
    216   msg.msg_controllen = kControlMsgSize;
    217 
    218   const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0));
    219   if (msg_size != expected_msg_size)
    220     return true;
    221 
    222   if (msg.msg_controllen != kControlMsgSize ||
    223       msg.msg_flags & ~MSG_TRUNC)
    224     return true;
    225 
    226   // Walk the control payload and extract the file descriptor and validated pid.
    227   pid_t crashing_pid = -1;
    228   int signal_fd = -1;
    229   for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
    230        hdr = CMSG_NXTHDR(&msg, hdr)) {
    231     if (hdr->cmsg_level != SOL_SOCKET)
    232       continue;
    233     if (hdr->cmsg_type == SCM_RIGHTS) {
    234       const unsigned len = hdr->cmsg_len -
    235           (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
    236       assert(len % sizeof(int) == 0u);
    237       const unsigned num_fds = len / sizeof(int);
    238       if (num_fds > 1 || num_fds == 0) {
    239         // A nasty process could try and send us too many descriptors and
    240         // force a leak.
    241         for (unsigned i = 0; i < num_fds; ++i)
    242           close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]);
    243         return true;
    244       } else {
    245         signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
    246       }
    247     } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
    248       const struct ucred *cred =
    249           reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
    250       crashing_pid = cred->pid;
    251     }
    252   }
    253 
    254   if (crashing_pid == -1 || signal_fd == -1) {
    255     if (signal_fd)
    256       close(signal_fd);
    257     return true;
    258   }
    259 
    260   string minidump_filename;
    261   if (!MakeMinidumpFilename(minidump_filename))
    262     return true;
    263 
    264   if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
    265                                       crashing_pid, crash_context,
    266                                       kCrashContextSize)) {
    267     close(signal_fd);
    268     return true;
    269   }
    270 
    271   if (dump_callback_) {
    272     ClientInfo info(crashing_pid, this);
    273 
    274     dump_callback_(dump_context_, &info, &minidump_filename);
    275   }
    276 
    277   // Send the done signal to the process: it can exit now.
    278   // (Closing this will make the child's sys_read unblock and return 0.)
    279   close(signal_fd);
    280 
    281   return true;
    282 }
    283 
    284 bool
    285 CrashGenerationServer::ControlEvent(short revents)
    286 {
    287   if (POLLHUP & revents)
    288     return false;
    289   assert(POLLIN & revents);
    290 
    291   char command;
    292   if (read(control_pipe_in_, &command, 1))
    293     return false;
    294 
    295   switch (command) {
    296   case kCommandQuit:
    297     return false;
    298   default:
    299     assert(0);
    300   }
    301 
    302   return true;
    303 }
    304 
    305 bool
    306 CrashGenerationServer::MakeMinidumpFilename(string& outFilename)
    307 {
    308   GUID guid;
    309   char guidString[kGUIDStringLength+1];
    310 
    311   if (!(CreateGUID(&guid)
    312         && GUIDToString(&guid, guidString, sizeof(guidString))))
    313     return false;
    314 
    315   char path[PATH_MAX];
    316   snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
    317 
    318   outFilename = path;
    319   return true;
    320 }
    321 
    322 // static
    323 void*
    324 CrashGenerationServer::ThreadMain(void *arg)
    325 {
    326   reinterpret_cast<CrashGenerationServer*>(arg)->Run();
    327   return NULL;
    328 }
    329 
    330 }  // namespace google_breakpad
    331