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