LCOV - code coverage report
Current view: top level - toolkit/crashreporter/breakpad-client/linux/crash_generation - crash_generation_server.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 135 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "linux/crash_generation/crash_generation_server.h"
      45             : #include "linux/crash_generation/client_info.h"
      46             : #include "linux/handler/exception_handler.h"
      47             : #include "linux/handler/guid_generator.h"
      48             : #include "linux/minidump_writer/minidump_writer.h"
      49             : #include "common/linux/eintr_wrapper.h"
      50             : #include "common/linux/safe_readlink.h"
      51             : 
      52             : static const char kCommandQuit = 'x';
      53             : 
      54             : namespace google_breakpad {
      55             : 
      56           0 : 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           0 :   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           0 :     started_(false)
      71             : {
      72           0 :   if (dump_path)
      73           0 :     dump_dir_ = *dump_path;
      74             :   else
      75           0 :     dump_dir_ = "/tmp";
      76           0 : }
      77             : 
      78           0 : CrashGenerationServer::~CrashGenerationServer()
      79             : {
      80           0 :   if (started_)
      81           0 :     Stop();
      82           0 : }
      83             : 
      84             : bool
      85           0 : CrashGenerationServer::Start()
      86             : {
      87           0 :   if (started_ || 0 > server_fd_)
      88           0 :     return false;
      89             : 
      90             :   int control_pipe[2];
      91           0 :   if (pipe(control_pipe))
      92           0 :     return false;
      93             : 
      94           0 :   if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC))
      95           0 :     return false;
      96           0 :   if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC))
      97           0 :     return false;
      98             : 
      99           0 :   if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK))
     100           0 :     return false;
     101             : 
     102           0 :   control_pipe_in_ = control_pipe[0];
     103           0 :   control_pipe_out_ = control_pipe[1];
     104             : 
     105           0 :   if (pthread_create(&thread_, NULL,
     106             :                      ThreadMain, reinterpret_cast<void*>(this)))
     107           0 :     return false;
     108             : 
     109           0 :   started_ = true;
     110           0 :   return true;
     111             : }
     112             : 
     113             : void
     114           0 : CrashGenerationServer::Stop()
     115             : {
     116           0 :   assert(pthread_self() != thread_);
     117             : 
     118           0 :   if (!started_)
     119           0 :     return;
     120             : 
     121           0 :   HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1));
     122             : 
     123             :   void* dummy;
     124           0 :   pthread_join(thread_, &dummy);
     125             : 
     126           0 :   close(control_pipe_in_);
     127           0 :   close(control_pipe_out_);
     128             : 
     129           0 :   started_ = false;
     130             : }
     131             : 
     132             : //static
     133             : bool
     134           0 : CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
     135             : {
     136             :   int fds[2];
     137             : 
     138           0 :   if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds))
     139           0 :     return false;
     140             : 
     141             :   static const int on = 1;
     142             :   // Enable passcred on the server end of the socket
     143           0 :   if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)))
     144           0 :     return false;
     145             : 
     146           0 :   if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
     147           0 :     return false;
     148           0 :   if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
     149           0 :     return false;
     150             : 
     151           0 :   *client_fd = fds[0];
     152           0 :   *server_fd = fds[1];
     153           0 :   return true;
     154             : }
     155             : 
     156             : // The following methods/functions execute on the server thread
     157             : 
     158             : void
     159           0 : CrashGenerationServer::Run()
     160             : {
     161             :   struct pollfd pollfds[2];
     162           0 :   memset(&pollfds, 0, sizeof(pollfds));
     163             : 
     164           0 :   pollfds[0].fd = server_fd_;
     165           0 :   pollfds[0].events = POLLIN;
     166             : 
     167           0 :   pollfds[1].fd = control_pipe_in_;
     168           0 :   pollfds[1].events = POLLIN;
     169             : 
     170             :   while (true) {
     171             :     // infinite timeout
     172           0 :     int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
     173           0 :     if (-1 == nevents) {
     174           0 :       if (EINTR == errno) {
     175           0 :         continue;
     176             :       } else {
     177           0 :         return;
     178             :       }
     179             :     }
     180             : 
     181           0 :     if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
     182           0 :       return;
     183             : 
     184           0 :     if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
     185           0 :       return;
     186           0 :   }
     187             : }
     188             : 
     189             : bool
     190           0 : CrashGenerationServer::ClientEvent(short revents)
     191             : {
     192           0 :   if (POLLHUP & revents)
     193           0 :     return false;
     194           0 :   assert(POLLIN & revents);
     195             : 
     196             :   // A process has crashed and has signaled us by writing a datagram
     197             :   // to the death signal socket. The datagram contains the crash context needed
     198             :   // for writing the minidump as well as a file descriptor and a credentials
     199             :   // block so that they can't lie about their pid.
     200             : 
     201             :   // The length of the control message:
     202             :   static const unsigned kControlMsgSize =
     203             :       CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
     204             :   // The length of the regular payload:
     205             :   static const unsigned kCrashContextSize =
     206             :       sizeof(google_breakpad::ExceptionHandler::CrashContext);
     207             : 
     208           0 :   struct msghdr msg = {0};
     209             :   struct iovec iov[1];
     210             :   char crash_context[kCrashContextSize];
     211             :   char control[kControlMsgSize];
     212           0 :   const ssize_t expected_msg_size = sizeof(crash_context);
     213             : 
     214           0 :   iov[0].iov_base = crash_context;
     215           0 :   iov[0].iov_len = sizeof(crash_context);
     216           0 :   msg.msg_iov = iov;
     217           0 :   msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
     218           0 :   msg.msg_control = control;
     219           0 :   msg.msg_controllen = kControlMsgSize;
     220             : 
     221           0 :   const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0));
     222           0 :   if (msg_size != expected_msg_size)
     223           0 :     return true;
     224             : 
     225           0 :   if (msg.msg_controllen != kControlMsgSize ||
     226           0 :       msg.msg_flags & ~MSG_TRUNC)
     227           0 :     return true;
     228             : 
     229             :   // Walk the control payload and extract the file descriptor and validated pid.
     230           0 :   pid_t crashing_pid = -1;
     231           0 :   int signal_fd = -1;
     232           0 :   for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
     233             :        hdr = CMSG_NXTHDR(&msg, hdr)) {
     234           0 :     if (hdr->cmsg_level != SOL_SOCKET)
     235           0 :       continue;
     236           0 :     if (hdr->cmsg_type == SCM_RIGHTS) {
     237           0 :       const unsigned len = hdr->cmsg_len -
     238           0 :           (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
     239           0 :       assert(len % sizeof(int) == 0u);
     240           0 :       const unsigned num_fds = len / sizeof(int);
     241           0 :       if (num_fds > 1 || num_fds == 0) {
     242             :         // A nasty process could try and send us too many descriptors and
     243             :         // force a leak.
     244           0 :         for (unsigned i = 0; i < num_fds; ++i)
     245           0 :           close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]);
     246           0 :         return true;
     247             :       } else {
     248           0 :         signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
     249             :       }
     250           0 :     } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
     251             :       const struct ucred *cred =
     252           0 :           reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
     253           0 :       crashing_pid = cred->pid;
     254             :     }
     255             :   }
     256             : 
     257           0 :   if (crashing_pid == -1 || signal_fd == -1) {
     258           0 :     if (signal_fd)
     259           0 :       close(signal_fd);
     260           0 :     return true;
     261             :   }
     262             : 
     263           0 :   string minidump_filename;
     264           0 :   if (!MakeMinidumpFilename(minidump_filename))
     265           0 :     return true;
     266             : 
     267           0 :   if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
     268             :                                       crashing_pid, crash_context,
     269             :                                       kCrashContextSize)) {
     270           0 :     close(signal_fd);
     271           0 :     return true;
     272             :   }
     273             : 
     274           0 :   if (dump_callback_) {
     275           0 :     ClientInfo info(crashing_pid, this);
     276             : 
     277           0 :     dump_callback_(dump_context_, &info, &minidump_filename);
     278             :   }
     279             : 
     280             :   // Send the done signal to the process: it can exit now.
     281             :   // (Closing this will make the child's sys_read unblock and return 0.)
     282           0 :   close(signal_fd);
     283             : 
     284           0 :   return true;
     285             : }
     286             : 
     287             : bool
     288           0 : CrashGenerationServer::ControlEvent(short revents)
     289             : {
     290           0 :   if (POLLHUP & revents)
     291           0 :     return false;
     292           0 :   assert(POLLIN & revents);
     293             : 
     294             :   char command;
     295           0 :   if (read(control_pipe_in_, &command, 1))
     296           0 :     return false;
     297             : 
     298           0 :   switch (command) {
     299             :   case kCommandQuit:
     300           0 :     return false;
     301             :   default:
     302           0 :     assert(0);
     303             :   }
     304             : 
     305             :   return true;
     306             : }
     307             : 
     308             : bool
     309           0 : CrashGenerationServer::MakeMinidumpFilename(string& outFilename)
     310             : {
     311             :   GUID guid;
     312             :   char guidString[kGUIDStringLength+1];
     313             : 
     314           0 :   if (!(CreateGUID(&guid)
     315           0 :         && GUIDToString(&guid, guidString, sizeof(guidString))))
     316           0 :     return false;
     317             : 
     318             :   char path[PATH_MAX];
     319           0 :   snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
     320             : 
     321           0 :   outFilename = path;
     322           0 :   return true;
     323             : }
     324             : 
     325             : // static
     326             : void*
     327           0 : CrashGenerationServer::ThreadMain(void *arg)
     328             : {
     329           0 :   reinterpret_cast<CrashGenerationServer*>(arg)->Run();
     330           0 :   return NULL;
     331             : }
     332             : 
     333             : }  // namespace google_breakpad

Generated by: LCOV version 1.13