/thirdparty/breakpad/client/linux/crash_generation/crash_generation_server.cc

http://github.com/tomahawk-player/tomahawk · C++ · 467 lines · 332 code · 82 blank · 53 comment · 83 complexity · b1601509de111f3e739fba3ffb38e1be MD5 · raw file

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