| Index: mojo/edk/embedder/platform_channel_utils_posix.cc
|
| diff --git a/mojo/edk/embedder/platform_channel_utils_posix.cc b/mojo/edk/embedder/platform_channel_utils_posix.cc
|
| index 3171844f67c7efd3b85bfc6fc55ab91d67b9c292..9fda89ebb65c54920c63619b63333feb72f12ff4 100644
|
| --- a/mojo/edk/embedder/platform_channel_utils_posix.cc
|
| +++ b/mojo/edk/embedder/platform_channel_utils_posix.cc
|
| @@ -8,9 +8,13 @@
|
| #include <sys/socket.h>
|
| #include <unistd.h>
|
|
|
| +#include <utility>
|
| +
|
| +#include "base/files/file_util.h"
|
| #include "base/logging.h"
|
| #include "base/posix/eintr_wrapper.h"
|
| #include "build/build_config.h"
|
| +#include "mojo/edk/embedder/scoped_platform_handle.h"
|
|
|
| #if !defined(OS_NACL)
|
| #include <sys/uio.h>
|
| @@ -22,6 +26,55 @@
|
|
|
| namespace mojo {
|
| namespace edk {
|
| +namespace {
|
| +
|
| +#if !defined(OS_NACL)
|
| +bool IsRecoverableError() {
|
| + return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE ||
|
| + errno == ENOMEM || errno == ENOBUFS;
|
| +}
|
| +
|
| +bool GetPeerEuid(PlatformHandle handle, uid_t* peer_euid) {
|
| + DCHECK(peer_euid);
|
| +#if defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_FREEBSD)
|
| + uid_t socket_euid;
|
| + gid_t socket_gid;
|
| + if (getpeereid(handle.handle, &socket_euid, &socket_gid) < 0) {
|
| + PLOG(ERROR) << "getpeereid " << handle.handle;
|
| + return false;
|
| + }
|
| + *peer_euid = socket_euid;
|
| + return true;
|
| +#else
|
| + struct ucred cred;
|
| + socklen_t cred_len = sizeof(cred);
|
| + if (getsockopt(handle.handle, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) <
|
| + 0) {
|
| + PLOG(ERROR) << "getsockopt " << handle.handle;
|
| + return false;
|
| + }
|
| + if (static_cast<unsigned>(cred_len) < sizeof(cred)) {
|
| + NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
|
| + return false;
|
| + }
|
| + *peer_euid = cred.uid;
|
| + return true;
|
| +#endif
|
| +}
|
| +
|
| +bool IsPeerAuthorized(PlatformHandle peer_handle) {
|
| + uid_t peer_euid;
|
| + if (!GetPeerEuid(peer_handle, &peer_euid))
|
| + return false;
|
| + if (peer_euid != geteuid()) {
|
| + DLOG(ERROR) << "Client euid is not authorised";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +#endif // !defined(OS_NACL)
|
| +
|
| +} // namespace
|
|
|
| // On Linux, |SIGPIPE| is suppressed by passing |MSG_NOSIGNAL| to
|
| // |send()|/|sendmsg()|. (There is no way of suppressing |SIGPIPE| on
|
| @@ -193,5 +246,36 @@ ssize_t PlatformChannelRecvmsg(PlatformHandle h,
|
| return result;
|
| }
|
|
|
| +bool ServerAcceptConnection(PlatformHandle server_handle,
|
| + ScopedPlatformHandle* connection_handle) {
|
| + DCHECK(server_handle.is_valid());
|
| + connection_handle->reset();
|
| +#if defined(OS_NACL)
|
| + NOTREACHED();
|
| + return false;
|
| +#else
|
| + ScopedPlatformHandle accept_handle(
|
| + PlatformHandle(HANDLE_EINTR(accept(server_handle.handle, NULL, 0))));
|
| + if (!accept_handle.is_valid())
|
| + return IsRecoverableError();
|
| +
|
| + // Verify that the IPC channel peer is running as the same user.
|
| + if (!IsPeerAuthorized(accept_handle.get())) {
|
| + return true;
|
| + }
|
| +
|
| + if (!base::SetNonBlocking(accept_handle.get().handle)) {
|
| + PLOG(ERROR) << "base::SetNonBlocking() failed "
|
| + << accept_handle.get().handle;
|
| + // It's safe to keep listening on |server_handle| even if the attempt to set
|
| + // O_NONBLOCK failed on the client fd.
|
| + return true;
|
| + }
|
| +
|
| + *connection_handle = std::move(accept_handle);
|
| + return true;
|
| +#endif // defined(OS_NACL)
|
| +}
|
| +
|
| } // namespace edk
|
| } // namespace mojo
|
|
|