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 "client/linux/crash_generation/crash_generation_server.h"
43 : #include "client/linux/crash_generation/client_info.h"
44 : #include "client/linux/handler/exception_handler.h"
45 : #include "client/linux/minidump_writer/minidump_writer.h"
46 : #include "common/linux/eintr_wrapper.h"
47 : #include "common/linux/guid_creator.h"
48 :
49 : static const char kCommandQuit = 'x';
50 :
51 : static bool
52 0 : GetInodeForFileDescriptor(ino_t* inode_out, int fd)
53 : {
54 0 : assert(inode_out);
55 :
56 : struct stat buf;
57 0 : if (fstat(fd, &buf) < 0)
58 0 : return false;
59 :
60 0 : if (!S_ISSOCK(buf.st_mode))
61 0 : return false;
62 :
63 0 : *inode_out = buf.st_ino;
64 0 : return true;
65 : }
66 :
67 : // expected prefix of the target of the /proc/self/fd/%d link for a socket
68 : static const char kSocketLinkPrefix[] = "socket:[";
69 :
70 : // Parse a symlink in /proc/pid/fd/$x and return the inode number of the
71 : // socket.
72 : // inode_out: (output) set to the inode number on success
73 : // path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor)
74 : static bool
75 0 : GetInodeForProcPath(ino_t* inode_out, const char* path)
76 : {
77 0 : assert(inode_out);
78 0 : assert(path);
79 :
80 : char buf[256];
81 0 : const ssize_t n = readlink(path, buf, sizeof(buf) - 1);
82 0 : if (n == -1) {
83 0 : return false;
84 : }
85 0 : buf[n] = 0;
86 :
87 0 : if (0 != memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) {
88 0 : return false;
89 : }
90 :
91 : char* endptr;
92 : const u_int64_t inode_ul =
93 0 : strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10);
94 0 : if (*endptr != ']')
95 0 : return false;
96 :
97 0 : if (inode_ul == ULLONG_MAX) {
98 0 : return false;
99 : }
100 :
101 0 : *inode_out = inode_ul;
102 0 : return true;
103 : }
104 :
105 : static bool
106 0 : FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode)
107 : {
108 0 : assert(pid_out);
109 0 : bool already_found = false;
110 :
111 0 : DIR* proc = opendir("/proc");
112 0 : if (!proc) {
113 0 : return false;
114 : }
115 :
116 0 : std::vector<pid_t> pids;
117 :
118 : struct dirent* dent;
119 0 : while ((dent = readdir(proc))) {
120 : char* endptr;
121 0 : const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10);
122 0 : if (pid_ul == ULONG_MAX || '\0' != *endptr)
123 0 : continue;
124 0 : pids.push_back(pid_ul);
125 : }
126 0 : closedir(proc);
127 :
128 0 : for (std::vector<pid_t>::const_iterator
129 0 : i = pids.begin(); i != pids.end(); ++i) {
130 0 : const pid_t current_pid = *i;
131 : char buf[256];
132 0 : snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid);
133 0 : DIR* fd = opendir(buf);
134 0 : if (!fd)
135 0 : continue;
136 :
137 0 : while ((dent = readdir(fd))) {
138 0 : if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid,
139 0 : dent->d_name) >= static_cast<int>(sizeof(buf))) {
140 0 : continue;
141 : }
142 :
143 : ino_t fd_inode;
144 0 : if (GetInodeForProcPath(&fd_inode, buf)
145 : && fd_inode == socket_inode) {
146 0 : if (already_found) {
147 0 : closedir(fd);
148 0 : return false;
149 : }
150 :
151 0 : already_found = true;
152 0 : *pid_out = current_pid;
153 0 : break;
154 : }
155 : }
156 :
157 0 : closedir(fd);
158 : }
159 :
160 0 : return already_found;
161 : }
162 :
163 : namespace google_breakpad {
164 :
165 0 : CrashGenerationServer::CrashGenerationServer(
166 : const int listen_fd,
167 : OnClientDumpRequestCallback dump_callback,
168 : void* dump_context,
169 : OnClientExitingCallback exit_callback,
170 : void* exit_context,
171 : bool generate_dumps,
172 : const std::string* dump_path) :
173 : server_fd_(listen_fd),
174 : dump_callback_(dump_callback),
175 : dump_context_(dump_context),
176 : exit_callback_(exit_callback),
177 : exit_context_(exit_context),
178 : generate_dumps_(generate_dumps),
179 0 : started_(false)
180 : {
181 0 : if (dump_path)
182 0 : dump_dir_ = *dump_path;
183 : else
184 0 : dump_dir_ = "/tmp";
185 0 : }
186 :
187 0 : CrashGenerationServer::~CrashGenerationServer()
188 : {
189 0 : if (started_)
190 0 : Stop();
191 0 : }
192 :
193 : bool
194 0 : CrashGenerationServer::Start()
195 : {
196 0 : if (started_ || 0 > server_fd_)
197 0 : return false;
198 :
199 : int control_pipe[2];
200 0 : if (pipe(control_pipe))
201 0 : return false;
202 :
203 0 : if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC))
204 0 : return false;
205 0 : if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC))
206 0 : return false;
207 :
208 0 : if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK))
209 0 : return false;
210 :
211 0 : control_pipe_in_ = control_pipe[0];
212 0 : control_pipe_out_ = control_pipe[1];
213 :
214 0 : if (pthread_create(&thread_, NULL,
215 0 : ThreadMain, reinterpret_cast<void*>(this)))
216 0 : return false;
217 :
218 0 : started_ = true;
219 0 : return true;
220 : }
221 :
222 : void
223 0 : CrashGenerationServer::Stop()
224 : {
225 0 : assert(pthread_self() != thread_);
226 :
227 0 : if (!started_)
228 0 : return;
229 :
230 0 : HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1));
231 :
232 : void* dummy;
233 0 : pthread_join(thread_, &dummy);
234 :
235 0 : started_ = false;
236 : }
237 :
238 : //static
239 : bool
240 0 : CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
241 : {
242 : int fds[2];
243 :
244 0 : if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds))
245 0 : return false;
246 :
247 : static const int on = 1;
248 : // Enable passcred on the server end of the socket
249 0 : if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)))
250 0 : return false;
251 :
252 0 : if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
253 0 : return false;
254 0 : if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
255 0 : return false;
256 :
257 0 : *client_fd = fds[0];
258 0 : *server_fd = fds[1];
259 0 : return true;
260 : }
261 :
262 : // The following methods/functions execute on the server thread
263 :
264 : void
265 0 : CrashGenerationServer::Run()
266 : {
267 : struct pollfd pollfds[2];
268 0 : memset(&pollfds, 0, sizeof(pollfds));
269 :
270 0 : pollfds[0].fd = server_fd_;
271 0 : pollfds[0].events = POLLIN;
272 :
273 0 : pollfds[1].fd = control_pipe_in_;
274 0 : pollfds[1].events = POLLIN;
275 :
276 0 : while (true) {
277 : // infinite timeout
278 0 : int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
279 0 : if (-1 == nevents) {
280 0 : if (EINTR == errno) {
281 0 : continue;
282 : } else {
283 0 : return;
284 : }
285 : }
286 :
287 0 : if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
288 0 : return;
289 :
290 0 : if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
291 0 : return;
292 : }
293 : }
294 :
295 : bool
296 0 : CrashGenerationServer::ClientEvent(short revents)
297 : {
298 0 : if (POLLHUP & revents)
299 0 : return false;
300 0 : assert(POLLIN & revents);
301 :
302 : // A process has crashed and has signaled us by writing a datagram
303 : // to the death signal socket. The datagram contains the crash context needed
304 : // for writing the minidump as well as a file descriptor and a credentials
305 : // block so that they can't lie about their pid.
306 :
307 : // The length of the control message:
308 : static const unsigned kControlMsgSize =
309 : CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
310 : // The length of the regular payload:
311 : static const unsigned kCrashContextSize =
312 : sizeof(google_breakpad::ExceptionHandler::CrashContext);
313 :
314 0 : struct msghdr msg = {0};
315 : struct iovec iov[1];
316 : char crash_context[kCrashContextSize];
317 : char control[kControlMsgSize];
318 0 : const ssize_t expected_msg_size = sizeof(crash_context);
319 :
320 0 : iov[0].iov_base = crash_context;
321 0 : iov[0].iov_len = sizeof(crash_context);
322 0 : msg.msg_iov = iov;
323 0 : msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
324 0 : msg.msg_control = control;
325 0 : msg.msg_controllen = kControlMsgSize;
326 :
327 0 : const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0));
328 0 : if (msg_size != expected_msg_size)
329 0 : return true;
330 :
331 0 : if (msg.msg_controllen != kControlMsgSize ||
332 : msg.msg_flags & ~MSG_TRUNC)
333 0 : return true;
334 :
335 : // Walk the control payload and extract the file descriptor and validated pid.
336 0 : pid_t crashing_pid = -1;
337 0 : int signal_fd = -1;
338 0 : for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
339 : hdr = CMSG_NXTHDR(&msg, hdr)) {
340 0 : if (hdr->cmsg_level != SOL_SOCKET)
341 0 : continue;
342 0 : if (hdr->cmsg_type == SCM_RIGHTS) {
343 : const unsigned len = hdr->cmsg_len -
344 0 : (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
345 0 : assert(len % sizeof(int) == 0u);
346 0 : const unsigned num_fds = len / sizeof(int);
347 0 : if (num_fds > 1 || num_fds == 0) {
348 : // A nasty process could try and send us too many descriptors and
349 : // force a leak.
350 0 : for (unsigned i = 0; i < num_fds; ++i)
351 0 : HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
352 0 : return true;
353 : } else {
354 0 : signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
355 : }
356 0 : } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
357 : const struct ucred *cred =
358 0 : reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
359 0 : crashing_pid = cred->pid;
360 : }
361 : }
362 :
363 0 : if (crashing_pid == -1 || signal_fd == -1) {
364 0 : if (signal_fd)
365 0 : HANDLE_EINTR(close(signal_fd));
366 0 : return true;
367 : }
368 :
369 : // Kernel bug workaround (broken in 2.6.30 at least):
370 : // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
371 : // namespaces. Thus |crashing_pid| might be garbage from our point of view.
372 : // In the future we can remove this workaround, but we have to wait a couple
373 : // of years to be sure that it's worked its way out into the world.
374 :
375 : ino_t inode_number;
376 0 : if (!GetInodeForFileDescriptor(&inode_number, signal_fd)) {
377 0 : HANDLE_EINTR(close(signal_fd));
378 0 : return true;
379 : }
380 :
381 0 : if (!FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) {
382 0 : HANDLE_EINTR(close(signal_fd));
383 0 : return true;
384 : }
385 :
386 0 : std::string minidump_filename;
387 0 : if (!MakeMinidumpFilename(minidump_filename))
388 0 : return true;
389 :
390 0 : if (generate_dumps_ &&
391 : !google_breakpad::WriteMinidump(minidump_filename.c_str(),
392 : crashing_pid, crash_context,
393 0 : kCrashContextSize)) {
394 0 : HANDLE_EINTR(close(signal_fd));
395 0 : return true;
396 : }
397 :
398 0 : if (dump_callback_) {
399 : ClientInfo info;
400 :
401 0 : info.crash_server_ = this;
402 0 : info.pid_ = crashing_pid;
403 0 : info.crash_context = crash_context;
404 0 : info.crash_context_size = kCrashContextSize;
405 :
406 0 : dump_callback_(dump_context_, &info, &minidump_filename);
407 : }
408 :
409 : // Send the done signal to the process: it can exit now.
410 0 : memset(&msg, 0, sizeof(msg));
411 : struct iovec done_iov;
412 0 : done_iov.iov_base = const_cast<char*>("\x42");
413 0 : done_iov.iov_len = 1;
414 0 : msg.msg_iov = &done_iov;
415 0 : msg.msg_iovlen = 1;
416 :
417 0 : HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
418 0 : HANDLE_EINTR(close(signal_fd));
419 :
420 0 : return true;
421 : }
422 :
423 : bool
424 0 : CrashGenerationServer::ControlEvent(short revents)
425 : {
426 0 : if (POLLHUP & revents)
427 0 : return false;
428 0 : assert(POLLIN & revents);
429 :
430 : char command;
431 0 : if (read(control_pipe_in_, &command, 1))
432 0 : return false;
433 :
434 0 : switch (command) {
435 : case kCommandQuit:
436 0 : return false;
437 : default:
438 0 : assert(0);
439 : }
440 :
441 : return true;
442 : }
443 :
444 : bool
445 0 : CrashGenerationServer::MakeMinidumpFilename(std::string& outFilename)
446 : {
447 : GUID guid;
448 : char guidString[kGUIDStringLength+1];
449 :
450 0 : if (!(CreateGUID(&guid)
451 0 : && GUIDToString(&guid, guidString, sizeof(guidString))))
452 0 : return false;
453 :
454 : char path[PATH_MAX];
455 0 : snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
456 :
457 0 : outFilename = path;
458 0 : return true;
459 : }
460 :
461 : // static
462 : void*
463 0 : CrashGenerationServer::ThreadMain(void *arg)
464 : {
465 0 : reinterpret_cast<CrashGenerationServer*>(arg)->Run();
466 0 : return NULL;
467 : }
468 :
469 : } // namespace google_breakpad
|