Commit 91b358ba authored by thestig@chromium.org's avatar thestig@chromium.org

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
parent ee757922
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment