diff options
-rw-r--r-- | ipc/ipc_channel.h | 20 | ||||
-rw-r--r-- | ipc/ipc_channel_posix.cc | 59 | ||||
-rw-r--r-- | ipc/ipc_channel_posix.h | 3 | ||||
-rw-r--r-- | ipc/ipc_channel_proxy.cc | 7 | ||||
-rw-r--r-- | ipc/ipc_channel_proxy.h | 1 |
5 files changed, 73 insertions, 17 deletions
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h index 91d9f2b..1550d49 100644 --- a/ipc/ipc_channel.h +++ b/ipc/ipc_channel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -67,7 +67,10 @@ class Channel : public Message::Sender { MODE_NO_FLAG = 0x0, MODE_SERVER_FLAG = 0x1, MODE_CLIENT_FLAG = 0x2, - MODE_NAMED_FLAG = 0x4 + MODE_NAMED_FLAG = 0x4, +#if defined(OS_POSIX) + MODE_OPEN_ACCESS_FLAG = 0x8, // Don't restrict access based on client UID. +#endif }; // Some Standard Modes @@ -82,6 +85,13 @@ class Channel : public Message::Sender { // MODE_NAMED_CLIENT is equivalent to MODE_CLIENT. MODE_NAMED_SERVER = MODE_SERVER_FLAG | MODE_NAMED_FLAG, MODE_NAMED_CLIENT = MODE_CLIENT_FLAG | MODE_NAMED_FLAG, +#if defined(OS_POSIX) + // An "open" named server accepts connections from ANY client. + // The caller must then implement their own access-control based on the + // client process' user Id. + MODE_OPEN_NAMED_SERVER = MODE_OPEN_ACCESS_FLAG | MODE_SERVER_FLAG | + MODE_NAMED_FLAG +#endif }; enum { @@ -152,10 +162,14 @@ class Channel : public Message::Sender { // currently connected. bool HasAcceptedConnection() const; + // Returns true if the peer process' effective user id can be determined, in + // which case the supplied client_euid is updated with it. + bool GetClientEuid(uid_t* client_euid) const; + // Closes any currently connected socket, and returns to a listening state // for more connections. void ResetToAcceptingConnectionState(); -#endif // defined(OS_POSIX) +#endif // defined(OS_POSIX) && !defined(OS_NACL) protected: // Used in Chrome by the TestSink to provide a dummy channel implementation diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc index d9156d7..22e4781 100644 --- a/ipc/ipc_channel_posix.cc +++ b/ipc/ipc_channel_posix.cc @@ -193,19 +193,6 @@ bool CreateServerUnixDomainSocket(const std::string& pipe_name, return false; } - // Explicitly set file system permissions on socket, mainly as a precaution - // for Chrome OS. - // Do not rely on these file permissions to provide security - the file is - // created during the above bind() call so there is still a window for - // malicious abuse because the file exists between bind() and chmod(). Also, - // the file permissions may not be enforced for unix sockets on all platforms. - if (chmod(pipe_name.c_str(), 0600)) { - PLOG(ERROR) << "chmod " << pipe_name; - if (HANDLE_EINTR(close(fd)) < 0) - PLOG(ERROR) << "close " << pipe_name; - return false; - } - // Start listening on the socket. const int listen_queue_length = 1; if (listen(fd, listen_queue_length) != 0) { @@ -938,6 +925,33 @@ bool Channel::ChannelImpl::HasAcceptedConnection() const { return AcceptsConnections() && pipe_ != -1; } +bool Channel::ChannelImpl::GetClientEuid(uid_t* client_euid) const { + DCHECK(HasAcceptedConnection()); +#if defined(OS_MACOSX) + uid_t peer_euid; + gid_t peer_gid; + if (getpeereid(pipe_, &peer_euid, &peer_gid) != 0) { + PLOG(ERROR) << "getpeereid " << pipe_; + return false; + } + *client_euid = peer_euid; + return true; +#else + struct ucred cred; + socklen_t cred_len = sizeof(cred); + if (getsockopt(pipe_, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) != 0) { + PLOG(ERROR) << "getsockopt " << pipe_; + return false; + } + if (cred_len < sizeof(cred)) { + NOTREACHED() << "Truncated ucred from SO_PEERCRED?"; + return false; + } + *client_euid = cred.uid; + return true; +#endif +} + void Channel::ChannelImpl::ResetToAcceptingConnectionState() { // Unregister libevent for the unix domain socket and close it. read_watcher_.StopWatchingFileDescriptor(); @@ -997,6 +1011,21 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { } pipe_ = new_pipe; + if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) { + // Verify that the IPC channel peer is running as the same user. + uid_t client_euid; + if (!GetClientEuid(&client_euid)) { + LOG(ERROR) << "Unable to query client euid"; + ResetToAcceptingConnectionState(); + return; + } + if (client_euid != geteuid()) { + LOG(WARNING) << "Client euid is not authorised"; + ResetToAcceptingConnectionState(); + return; + } + } + if (!AcceptConnection()) { NOTREACHED() << "AcceptConnection should not fail on server"; } @@ -1161,6 +1190,10 @@ bool Channel::HasAcceptedConnection() const { return channel_impl_->HasAcceptedConnection(); } +bool Channel::GetClientEuid(uid_t* client_euid) const { + return channel_impl_->GetClientEuid(client_euid); +} + void Channel::ResetToAcceptingConnectionState() { channel_impl_->ResetToAcceptingConnectionState(); } diff --git a/ipc/ipc_channel_posix.h b/ipc/ipc_channel_posix.h index b1c4c3b..f1cbd63 100644 --- a/ipc/ipc_channel_posix.h +++ b/ipc/ipc_channel_posix.h @@ -1,4 +1,4 @@ -// Copyright (c) 2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -53,6 +53,7 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher { int GetClientFileDescriptor() const; bool AcceptsConnections() const; bool HasAcceptedConnection() const; + bool GetClientEuid(uid_t* client_euid) const; void ResetToAcceptingConnectionState(); private: diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc index a92d511..c219829 100644 --- a/ipc/ipc_channel_proxy.cc +++ b/ipc/ipc_channel_proxy.cc @@ -375,6 +375,13 @@ int ChannelProxy::GetClientFileDescriptor() const { DCHECK(channel) << context_.get()->channel_id_; return channel->GetClientFileDescriptor(); } + +bool ChannelProxy::GetClientEuid(uid_t* client_euid) const { + Channel *channel = context_.get()->channel_.get(); + // Channel must have been created first. + DCHECK(channel) << context_.get()->channel_id_; + return channel->GetClientEuid(client_euid); +} #endif //----------------------------------------------------------------------------- diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h index 950edff..0c0176f 100644 --- a/ipc/ipc_channel_proxy.h +++ b/ipc/ipc_channel_proxy.h @@ -146,6 +146,7 @@ class ChannelProxy : public Message::Sender { #if defined(OS_POSIX) // Calls through to the underlying channel's methods. int GetClientFileDescriptor() const; + bool GetClientEuid(uid_t* client_euid) const; #endif // defined(OS_POSIX) protected: |