diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-12 02:39:31 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-12 02:39:31 +0000 |
commit | afb4bad25473e8bd8b310096c70d404b06765314 (patch) | |
tree | b55bd8bb99869535beacb2da2cc316c291a396b5 /chrome/common | |
parent | f8bae45bba9bfc60577e189c13dd18d91ac2642a (diff) | |
download | chromium_src-afb4bad25473e8bd8b310096c70d404b06765314.zip chromium_src-afb4bad25473e8bd8b310096c70d404b06765314.tar.gz chromium_src-afb4bad25473e8bd8b310096c70d404b06765314.tar.bz2 |
OSX: Workaround CMSG_FIRSTHDR bug
On OSX, CMSG_FIRSTHDR will return a pointer into the control buffer
space when controllen == 0. We work around by testing for a non-zero
controllen before trying to parse control messages.
Test case:
int
main() {
struct msghdr msg;
msg.msg_control = &msg;
msg.msg_controllen = 0;
if (CMSG_FIRSTHDR(&msg))
printf("Bug found!\n");
}
Review URL: http://codereview.chromium.org/21283
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9640 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/ipc_channel_posix.cc | 58 |
1 files changed, 41 insertions, 17 deletions
diff --git a/chrome/common/ipc_channel_posix.cc b/chrome/common/ipc_channel_posix.cc index d9f44dd..b46024c 100644 --- a/chrome/common/ipc_channel_posix.cc +++ b/chrome/common/ipc_channel_posix.cc @@ -406,24 +406,40 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() { // walk the list of control messages and, if we find an array of file // descriptors, save a pointer to the array - for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); - DCHECK(payload_len % sizeof(int) == 0); - wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); - num_wire_fds = payload_len / 4; - - if (msg.msg_flags & MSG_CTRUNC) { - LOG(ERROR) << "SCM_RIGHTS message was truncated" - << " cmsg_len:" << cmsg->cmsg_len - << " fd:" << pipe_; - for (unsigned i = 0; i < num_wire_fds; ++i) - close(wire_fds[i]); - return false; + + // This next if statement is to work around an OSX issue where + // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0. + // Here's a test case: + // + // int main() { + // struct msghdr msg; + // msg.msg_control = &msg; + // msg.msg_controllen = 0; + // if (CMSG_FIRSTHDR(&msg)) + // printf("Bug found!\n"); + // } + if (msg.msg_controllen > 0) { + // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0 + // and will return a pointer into nowhere. + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); + DCHECK(payload_len % sizeof(int) == 0); + wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); + num_wire_fds = payload_len / 4; + + if (msg.msg_flags & MSG_CTRUNC) { + LOG(ERROR) << "SCM_RIGHTS message was truncated" + << " cmsg_len:" << cmsg->cmsg_len + << " fd:" << pipe_; + for (unsigned i = 0; i < num_wire_fds; ++i) + close(wire_fds[i]); + return false; + } + break; } - break; } } @@ -509,6 +525,14 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() { input_overflow_buf_.assign(p, end - p); input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]); + // When the input data buffer is empty, the overflow fds should be too. If + // this is not the case, we probably have a rogue renderer which is trying + // to fill our descriptor table. + if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) { + // We close these descriptors in Close() + return false; + } + bytes_read = 0; // Get more data. } |