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