summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/ipc_channel.h20
-rw-r--r--ipc/ipc_channel_posix.cc59
-rw-r--r--ipc/ipc_channel_posix.h3
-rw-r--r--ipc/ipc_channel_proxy.cc7
-rw-r--r--ipc/ipc_channel_proxy.h1
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: