diff options
author | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-06 05:23:59 +0000 |
---|---|---|
committer | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-06 05:23:59 +0000 |
commit | 91b358ba1cdf6ec4b935167cea9709478272d502 (patch) | |
tree | bafed98f7c2feb978d435e0a36f75ffc2c73fe83 /components/breakpad/browser | |
parent | ee7579229ff7e9e5ae28bf53aea069251499d7da (diff) | |
download | chromium_src-91b358ba1cdf6ec4b935167cea9709478272d502.zip chromium_src-91b358ba1cdf6ec4b935167cea9709478272d502.tar.gz chromium_src-91b358ba1cdf6ec4b935167cea9709478272d502.tar.bz2 |
Linux: Improve message handling in CrashHandlerHostLinux to prevent file descriptor leaks.
BUG=373091
Review URL: https://codereview.chromium.org/321433003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275339 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components/breakpad/browser')
-rw-r--r-- | components/breakpad/browser/crash_handler_host_linux.cc | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/components/breakpad/browser/crash_handler_host_linux.cc b/components/breakpad/browser/crash_handler_host_linux.cc index 94e1974..543ebc4 100644 --- a/components/breakpad/browser/crash_handler_host_linux.cc +++ b/components/breakpad/browser/crash_handler_host_linux.cc @@ -14,6 +14,7 @@ #include "base/bind_helpers.h" #include "base/file_util.h" #include "base/files/file_path.h" +#include "base/files/scoped_file.h" #include "base/format_macros.h" #include "base/linux_util.h" #include "base/logging.h" @@ -195,7 +196,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { msg.msg_controllen = kControlMsgSize; const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0)); - if (msg_size != expected_msg_size) { + if (msg_size < 0) { LOG(ERROR) << "Error reading from death signal socket. Crash dumping" << " is disabled." << " msg_size:" << msg_size @@ -203,9 +204,46 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { file_descriptor_watcher_.StopWatchingFileDescriptor(); return; } + const bool bad_message = (msg_size != expected_msg_size || + msg.msg_controllen != kControlMsgSize || + msg.msg_flags & ~MSG_TRUNC); + base::ScopedFD signal_fd; + pid_t crashing_pid = -1; + if (msg.msg_controllen > 0) { + // Walk the control payload and extract the file descriptor and + // validated pid. + for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr; + hdr = CMSG_NXTHDR(&msg, hdr)) { + if (hdr->cmsg_level != SOL_SOCKET) + continue; + if (hdr->cmsg_type == SCM_RIGHTS) { + const size_t len = hdr->cmsg_len - + (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr); + DCHECK_EQ(0U, len % sizeof(int)); + const size_t num_fds = len / sizeof(int); + if (num_fds != kNumFDs) { + // A nasty process could try and send us too many descriptors and + // force a leak. + LOG(ERROR) << "Death signal contained wrong number of descriptors;" + << " num_fds:" << num_fds; + for (size_t i = 0; i < num_fds; ++i) + close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]); + return; + } + DCHECK(!signal_fd.is_valid()); + int fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0]; + DCHECK_GE(fd, 0); // The kernel should never send a negative fd. + signal_fd.reset(fd); + } else if (hdr->cmsg_type == SCM_CREDENTIALS) { + DCHECK_EQ(-1, crashing_pid); + const struct ucred *cred = + reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); + crashing_pid = cred->pid; + } + } + } - if (msg.msg_controllen != kControlMsgSize || - msg.msg_flags & ~MSG_TRUNC) { + if (bad_message) { LOG(ERROR) << "Received death signal message with the wrong size;" << " msg.msg_controllen:" << msg.msg_controllen << " msg.msg_flags:" << msg.msg_flags @@ -213,42 +251,9 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { << " kControlMsgSize:" << kControlMsgSize; return; } - - // Walk the control payload an extract the file descriptor and validated pid. - pid_t crashing_pid = -1; - int signal_fd = -1; - for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr; - hdr = CMSG_NXTHDR(&msg, hdr)) { - if (hdr->cmsg_level != SOL_SOCKET) - continue; - if (hdr->cmsg_type == SCM_RIGHTS) { - const size_t len = hdr->cmsg_len - - (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr); - DCHECK_EQ(0U, len % sizeof(int)); - const size_t num_fds = len / sizeof(int); - if (num_fds != kNumFDs) { - // A nasty process could try and send us too many descriptors and - // force a leak. - LOG(ERROR) << "Death signal contained wrong number of descriptors;" - << " num_fds:" << num_fds; - for (size_t i = 0; i < num_fds; ++i) - close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]); - return; - } else { - signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0]; - } - } else if (hdr->cmsg_type == SCM_CREDENTIALS) { - const struct ucred *cred = - reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); - crashing_pid = cred->pid; - } - } - - if (crashing_pid == -1 || signal_fd == -1) { + if (crashing_pid == -1 || !signal_fd.is_valid()) { LOG(ERROR) << "Death signal message didn't contain all expected control" << " messages"; - if (signal_fd >= 0) - close(signal_fd); return; } @@ -326,7 +331,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { base::Passed(&info), base::Passed(&crash_context), crashing_pid, - signal_fd)); + signal_fd.release())); } void CrashHandlerHostLinux::WriteDumpFile(scoped_ptr<BreakpadInfo> info, |