diff options
author | David Brazdil <dbrazdil@google.com> | 2022-10-08 15:36:02 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-10-08 15:36:02 +0000 |
commit | 08178a7279c08cdbe09bc186735063a43621f9bc (patch) | |
tree | 71d752446e669606f8d4d2b4cf8e4b3a47160e25 | |
parent | 50da0077f22537c281b6cc31ca09acc53b367450 (diff) | |
parent | 21c887c5a09040bf41d272a9e729119956e48a3f (diff) | |
download | native-08178a7279c08cdbe09bc186735063a43621f9bc.tar.gz |
Merge "RpcBinder: Add AF_UNIX socketpair transport"
-rw-r--r-- | libs/binder/OS.cpp | 99 | ||||
-rw-r--r-- | libs/binder/OS.h | 8 | ||||
-rw-r--r-- | libs/binder/RpcServer.cpp | 72 | ||||
-rw-r--r-- | libs/binder/RpcSession.cpp | 29 | ||||
-rw-r--r-- | libs/binder/RpcTransportRaw.cpp | 107 | ||||
-rw-r--r-- | libs/binder/include/binder/RpcServer.h | 19 | ||||
-rw-r--r-- | libs/binder/include/binder/RpcSession.h | 7 | ||||
-rw-r--r-- | libs/binder/tests/BinderRpcTestServerConfig.aidl | 1 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 91 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTestCommon.h | 5 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTestService.cpp | 4 | ||||
-rw-r--r-- | libs/binder/trusty/OS.cpp | 14 |
12 files changed, 336 insertions, 120 deletions
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp index 24ce2bb465..77e401f83e 100644 --- a/libs/binder/OS.cpp +++ b/libs/binder/OS.cpp @@ -18,6 +18,7 @@ #include <android-base/file.h> #include <binder/RpcTransportRaw.h> +#include <log/log.h> #include <string.h> using android::base::ErrnoError; @@ -25,6 +26,9 @@ using android::base::Result; namespace android { +// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. +constexpr size_t kMaxFdsPerMsg = 253; + Result<void> setNonBlocking(android::base::borrowed_fd fd) { int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL)); if (flags == -1) { @@ -63,4 +67,99 @@ std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() { return RpcTransportCtxFactoryRaw::make(); } +int sendMessageOnSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { + if (ancillaryFds != nullptr && !ancillaryFds->empty()) { + if (ancillaryFds->size() > kMaxFdsPerMsg) { + errno = EINVAL; + return -1; + } + + // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then + // use memcpy. + int fds[kMaxFdsPerMsg]; + for (size_t i = 0; i < ancillaryFds->size(); i++) { + fds[i] = std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i)); + } + const size_t fdsByteSize = sizeof(int) * ancillaryFds->size(); + + alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)]; + + msghdr msg{ + .msg_iov = iovs, + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + .msg_control = msgControlBuf, + .msg_controllen = sizeof(msgControlBuf), + }; + + cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(fdsByteSize); + memcpy(CMSG_DATA(cmsg), fds, fdsByteSize); + + msg.msg_controllen = CMSG_SPACE(fdsByteSize); + return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC)); + } + + msghdr msg{ + .msg_iov = iovs, + // posix uses int, glibc uses size_t. niovs is a + // non-negative int and can be cast to either. + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + }; + return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); +} + +int receiveMessageFromSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { + if (ancillaryFds != nullptr) { + int fdBuffer[kMaxFdsPerMsg]; + alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))]; + + msghdr msg{ + .msg_iov = iovs, + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + .msg_control = msgControlBuf, + .msg_controllen = sizeof(msgControlBuf), + }; + ssize_t processSize = TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); + if (processSize < 0) { + return -1; + } + + for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks + // application devs to memcpy the data to ensure memory alignment. + size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0); + LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // validity check + memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen); + size_t fdCount = dataLen / sizeof(int); + ancillaryFds->reserve(ancillaryFds->size() + fdCount); + for (size_t i = 0; i < fdCount; i++) { + ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i])); + } + break; + } + } + + if (msg.msg_flags & MSG_CTRUNC) { + errno = EPIPE; + return -1; + } + return processSize; + } + msghdr msg{ + .msg_iov = iovs, + // posix uses int, glibc uses size_t. niovs is a + // non-negative int and can be cast to either. + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + }; + + return TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); +} + } // namespace android diff --git a/libs/binder/OS.h b/libs/binder/OS.h index 5ab8bab0e7..0d38968ade 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -33,4 +33,12 @@ status_t dupFileDescriptor(int oldFd, int* newFd); std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory(); +int sendMessageOnSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); + +int receiveMessageFromSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); + } // namespace android diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index e581d0b16c..83d0de7835 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -37,6 +37,7 @@ #include "OS.h" #include "RpcSocketAddress.h" #include "RpcState.h" +#include "RpcTransportUtils.h" #include "RpcWireFormat.h" #include "Utils.h" @@ -61,6 +62,10 @@ sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTranspo return sp<RpcServer>::make(std::move(ctx)); } +status_t RpcServer::setupUnixDomainSocketBootstrapServer(unique_fd bootstrapFd) { + return setupExternalServer(std::move(bootstrapFd), &RpcServer::recvmsgSocketConnection); +} + status_t RpcServer::setupUnixDomainServer(const char* path) { return setupSocketServer(UnixSocketAddress(path)); } @@ -177,11 +182,50 @@ void RpcServer::start() { rpcJoinIfSingleThreaded(*mJoinThread); } +status_t RpcServer::acceptSocketConnection(const RpcServer& server, RpcTransportFd* out) { + RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY( + accept4(server.mServer.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK)))); + if (clientSocket.fd < 0) { + int savedErrno = errno; + ALOGE("Could not accept4 socket: %s", strerror(savedErrno)); + return -savedErrno; + } + + *out = std::move(clientSocket); + return OK; +} + +status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out) { + int zero = 0; + iovec iov{&zero, sizeof(zero)}; + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + + if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) { + int savedErrno = errno; + ALOGE("Failed recvmsg: %s", strerror(savedErrno)); + return -savedErrno; + } + if (fds.size() != 1) { + ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size()); + return -EINVAL; + } + + unique_fd fd(std::move(std::get<unique_fd>(fds.back()))); + if (auto res = setNonBlocking(fd); !res.ok()) { + ALOGE("Failed setNonBlocking: %s", res.error().message().c_str()); + return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code(); + } + + *out = RpcTransportFd(std::move(fd)); + return OK; +} + void RpcServer::join() { { RpcMutexLockGuard _l(mLock); LOG_ALWAYS_FATAL_IF(!mServer.fd.ok(), "RpcServer must be setup to join."); + LOG_ALWAYS_FATAL_IF(mAcceptFn == nullptr, "RpcServer must have an accept() function"); LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined"); mJoinThreadRunning = true; mShutdownTrigger = FdTrigger::make(); @@ -192,20 +236,19 @@ void RpcServer::join() { while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) { std::array<uint8_t, kRpcAddressSize> addr; static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small"); - socklen_t addrLen = addr.size(); - RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY( - accept4(mServer.fd.get(), reinterpret_cast<sockaddr*>(addr.data()), &addrLen, - SOCK_CLOEXEC | SOCK_NONBLOCK)))); - - LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)), - "Truncated address"); - if (clientSocket.fd < 0) { - ALOGE("Could not accept4 socket: %s", strerror(errno)); + RpcTransportFd clientSocket; + if (mAcceptFn(*this, &clientSocket) != OK) { + continue; + } + if (getpeername(clientSocket.fd.get(), reinterpret_cast<sockaddr*>(addr.data()), + &addrLen)) { + ALOGE("Could not getpeername socket: %s", strerror(errno)); continue; } - LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get()); + + LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get()); { RpcMutexLockGuard _l(mLock); @@ -550,16 +593,23 @@ unique_fd RpcServer::releaseServer() { return std::move(mServer.fd); } -status_t RpcServer::setupExternalServer(base::unique_fd serverFd) { +status_t RpcServer::setupExternalServer( + base::unique_fd serverFd, + std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn) { RpcMutexLockGuard _l(mLock); if (mServer.fd.ok()) { ALOGE("Each RpcServer can only have one server."); return INVALID_OPERATION; } mServer = std::move(serverFd); + mAcceptFn = std::move(acceptFn); return OK; } +status_t RpcServer::setupExternalServer(base::unique_fd serverFd) { + return setupExternalServer(std::move(serverFd), &RpcServer::acceptSocketConnection); +} + bool RpcServer::hasActiveRequests() { RpcMutexLockGuard _l(mLock); for (const auto& [_, session] : mSessions) { diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index 49843e5953..ff50c16102 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -41,6 +41,7 @@ #include "OS.h" #include "RpcSocketAddress.h" #include "RpcState.h" +#include "RpcTransportUtils.h" #include "RpcWireFormat.h" #include "Utils.h" @@ -147,6 +148,34 @@ status_t RpcSession::setupUnixDomainClient(const char* path) { return setupSocketClient(UnixSocketAddress(path)); } +status_t RpcSession::setupUnixDomainSocketBootstrapClient(unique_fd bootstrapFd) { + mBootstrapTransport = + mCtx->newTransport(RpcTransportFd(std::move(bootstrapFd)), mShutdownTrigger.get()); + return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) { + int socks[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, socks) < 0) { + int savedErrno = errno; + ALOGE("Failed socketpair: %s", strerror(savedErrno)); + return -savedErrno; + } + unique_fd clientFd(socks[0]), serverFd(socks[1]); + + int zero = 0; + iovec iov{&zero, sizeof(zero)}; + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + fds.push_back(std::move(serverFd)); + + status_t status = mBootstrapTransport->interruptableWriteFully(mShutdownTrigger.get(), &iov, + 1, std::nullopt, &fds); + if (status != OK) { + ALOGE("Failed to send fd over bootstrap transport: %s", strerror(-status)); + return status; + } + + return initAndAddConnection(RpcTransportFd(std::move(clientFd)), sessionId, incoming); + }); +} + status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) { return setupSocketClient(VsockSocketAddress(cid, port)); } diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index 65e8fac341..1912d140f4 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -23,6 +23,7 @@ #include <binder/RpcTransportRaw.h> #include "FdTrigger.h" +#include "OS.h" #include "RpcState.h" #include "RpcTransportUtils.h" @@ -30,9 +31,6 @@ namespace android { namespace { -// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. -constexpr size_t kMaxFdsPerMsg = 253; - // RpcTransport with TLS disabled. class RpcTransportRaw : public RpcTransport { public: @@ -63,57 +61,9 @@ public: override { bool sentFds = false; auto send = [&](iovec* iovs, int niovs) -> ssize_t { - if (ancillaryFds != nullptr && !ancillaryFds->empty() && !sentFds) { - if (ancillaryFds->size() > kMaxFdsPerMsg) { - // This shouldn't happen because we check the FD count in RpcState. - ALOGE("Saw too many file descriptors in RpcTransportCtxRaw: %zu (max is %zu). " - "Aborting session.", - ancillaryFds->size(), kMaxFdsPerMsg); - errno = EINVAL; - return -1; - } - - // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then - // use memcpy. - int fds[kMaxFdsPerMsg]; - for (size_t i = 0; i < ancillaryFds->size(); i++) { - fds[i] = std::visit([](const auto& fd) { return fd.get(); }, - ancillaryFds->at(i)); - } - const size_t fdsByteSize = sizeof(int) * ancillaryFds->size(); - - alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)]; - - msghdr msg{ - .msg_iov = iovs, - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - .msg_control = msgControlBuf, - .msg_controllen = sizeof(msgControlBuf), - }; - - cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(fdsByteSize); - memcpy(CMSG_DATA(cmsg), fds, fdsByteSize); - - msg.msg_controllen = CMSG_SPACE(fdsByteSize); - - ssize_t processedSize = TEMP_FAILURE_RETRY( - sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC)); - if (processedSize > 0) { - sentFds = true; - } - return processedSize; - } - - msghdr msg{ - .msg_iov = iovs, - // posix uses int, glibc uses size_t. niovs is a - // non-negative int and can be cast to either. - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - }; - return TEMP_FAILURE_RETRY(sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL)); + int ret = sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds); + sentFds |= ret > 0; + return ret; }; return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll); @@ -124,54 +74,7 @@ public: const std::optional<android::base::function_ref<status_t()>>& altPoll, std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { auto recv = [&](iovec* iovs, int niovs) -> ssize_t { - if (ancillaryFds != nullptr) { - int fdBuffer[kMaxFdsPerMsg]; - alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))]; - - msghdr msg{ - .msg_iov = iovs, - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - .msg_control = msgControlBuf, - .msg_controllen = sizeof(msgControlBuf), - }; - ssize_t processSize = - TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL)); - if (processSize < 0) { - return -1; - } - - for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks - // application devs to memcpy the data to ensure memory alignment. - size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0); - LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // sanity check - memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen); - size_t fdCount = dataLen / sizeof(int); - ancillaryFds->reserve(ancillaryFds->size() + fdCount); - for (size_t i = 0; i < fdCount; i++) { - ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i])); - } - break; - } - } - - if (msg.msg_flags & MSG_CTRUNC) { - ALOGE("msg was truncated. Aborting session."); - errno = EPIPE; - return -1; - } - - return processSize; - } - msghdr msg{ - .msg_iov = iovs, - // posix uses int, glibc uses size_t. niovs is a - // non-negative int and can be cast to either. - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - }; - return TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL)); + return receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); }; return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll); diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 2c99334fa4..81ae26a344 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -50,6 +50,17 @@ public: std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr); /** + * Creates an RPC server that bootstraps sessions using an existing + * Unix domain socket pair. + * + * Callers should create a pair of SOCK_STREAM Unix domain sockets, pass + * one to RpcServer::setupUnixDomainSocketBootstrapServer and the other + * to RpcSession::setupUnixDomainSocketBootstrapClient. Multiple client + * session can be created from the client end of the pair. + */ + [[nodiscard]] status_t setupUnixDomainSocketBootstrapServer(base::unique_fd serverFd); + + /** * This represents a session for responses, e.g.: * * process A serves binder a @@ -202,11 +213,18 @@ private: void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override; void onSessionIncomingThreadEnded() override; + status_t setupExternalServer( + base::unique_fd serverFd, + std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn); + static constexpr size_t kRpcAddressSize = 128; static void establishConnection( sp<RpcServer>&& server, RpcTransportFd clientFd, std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen, std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn); + static status_t acceptSocketConnection(const RpcServer& server, RpcTransportFd* out); + static status_t recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out); + [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address); const std::unique_ptr<RpcTransportCtx> mCtx; @@ -228,6 +246,7 @@ private: std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions; std::unique_ptr<FdTrigger> mShutdownTrigger; RpcConditionVariable mShutdownCv; + std::function<status_t(const RpcServer& server, RpcTransportFd* out)> mAcceptFn; }; } // namespace android diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index 1bd49750a7..5e5d4eafa6 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -117,6 +117,11 @@ public: [[nodiscard]] status_t setupUnixDomainClient(const char* path); /** + * Connects to an RPC server over a nameless Unix domain socket pair. + */ + [[nodiscard]] status_t setupUnixDomainSocketBootstrapClient(base::unique_fd bootstrap); + + /** * Connects to an RPC server at the CVD & port. */ [[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port); @@ -368,6 +373,8 @@ private: RpcConditionVariable mAvailableConnectionCv; // for mWaitingThreads + std::unique_ptr<RpcTransport> mBootstrapTransport; + struct ThreadState { size_t mWaitingThreads = 0; // hint index into clients, ++ when sending an async transaction diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl index 34d74bee0d..4cdeac4a97 100644 --- a/libs/binder/tests/BinderRpcTestServerConfig.aidl +++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl @@ -21,5 +21,6 @@ parcelable BinderRpcTestServerConfig { int rpcSecurity; int serverVersion; int vsockPort; + int unixBootstrapFd; // Inherited from parent @utf8InCpp String addr; } diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index d736cd2de7..72943051c7 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -254,6 +254,25 @@ static base::unique_fd connectTo(const RpcSocketAddress& addr) { return serverFd; } +static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) { + base::unique_fd sockClient, sockServer; + if (!base::Socketpair(SOCK_STREAM, &sockClient, &sockServer)) { + int savedErrno = errno; + LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno); + } + + int zero = 0; + iovec iov{&zero, sizeof(zero)}; + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + fds.emplace_back(std::move(sockServer)); + + if (sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { + int savedErrno = errno; + LOG(FATAL) << "Failed sendMessageOnSocket: " << strerror(savedErrno); + } + return std::move(sockClient); +} + using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd); @@ -274,7 +293,14 @@ public: // Whether the test params support sending FDs in parcels. bool supportsFdTransport() const { return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS && - (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX); + (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX || + socketType() == SocketType::UNIX_BOOTSTRAP); + } + + void SetUp() override { + if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) { + GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport"; + } } static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) { @@ -308,6 +334,14 @@ public: singleThreaded ? "_single_threaded" : "", noKernel ? "_no_kernel" : ""); + base::unique_fd bootstrapClientFd, bootstrapServerFd; + // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec. + // This is because we cannot pass ParcelFileDescriptor over a pipe. + if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) { + int savedErrno = errno; + LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno); + } + auto ret = ProcessSession{ .host = Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) { @@ -325,6 +359,7 @@ public: serverConfig.serverVersion = serverVersion; serverConfig.vsockPort = allocateVsockPort(); serverConfig.addr = allocateSocketAddress(); + serverConfig.unixBootstrapFd = bootstrapServerFd.get(); for (auto mode : options.serverSupportedFileDescriptorTransportModes) { serverConfig.serverSupportedFileDescriptorTransportModes.push_back( static_cast<int32_t>(mode)); @@ -374,6 +409,10 @@ public: case SocketType::UNIX: status = session->setupUnixDomainClient(serverConfig.addr.c_str()); break; + case SocketType::UNIX_BOOTSTRAP: + status = session->setupUnixDomainSocketBootstrapClient( + base::unique_fd(dup(bootstrapClientFd.get()))); + break; case SocketType::VSOCK: status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort); break; @@ -440,7 +479,8 @@ TEST_P(BinderRpc, SeparateRootObject) { } SocketType type = std::get<0>(GetParam()); - if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) { + if (type == SocketType::PRECONNECTED || type == SocketType::UNIX || + type == SocketType::UNIX_BOOTSTRAP) { // we can't get port numbers for unix sockets return; } @@ -1576,7 +1616,7 @@ static bool testSupportVsockLoopback() { } static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) { - std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET}; + std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET}; if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED); @@ -1777,6 +1817,8 @@ public: // A server that handles client socket connections. class Server { public: + using AcceptConnection = std::function<base::unique_fd(Server*)>; + explicit Server() {} Server(Server&&) = default; ~Server() { shutdownAndWait(); } @@ -1801,6 +1843,21 @@ public: return connectTo(UnixSocketAddress(addr.c_str())); }; } break; + case SocketType::UNIX_BOOTSTRAP: { + base::unique_fd bootstrapFdClient, bootstrapFdServer; + if (!base::Socketpair(SOCK_STREAM, &bootstrapFdClient, &bootstrapFdServer)) { + return AssertionFailure() << "Socketpair() failed"; + } + auto status = rpcServer->setupUnixDomainSocketBootstrapServer( + std::move(bootstrapFdServer)); + if (status != OK) { + return AssertionFailure() << "setupUnixDomainSocketBootstrapServer: " + << statusToString(status); + } + mBootstrapSocket = RpcTransportFd(std::move(bootstrapFdClient)); + mAcceptConnection = &Server::recvmsgServerConnection; + mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); }; + } break; case SocketType::VSOCK: { auto port = allocateVsockPort(); auto status = rpcServer->setupVsockServer(port); @@ -1848,14 +1905,33 @@ public: LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!"); mThread = std::make_unique<std::thread>(&Server::run, this); } + + base::unique_fd acceptServerConnection() { + return base::unique_fd(TEMP_FAILURE_RETRY( + accept4(mFd.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK))); + } + + base::unique_fd recvmsgServerConnection() { + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + int buf; + iovec iov{&buf, sizeof(buf)}; + + if (receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) { + int savedErrno = errno; + LOG(FATAL) << "Failed receiveMessage: " << strerror(savedErrno); + } + if (fds.size() != 1) { + LOG(FATAL) << "Expected one FD from receiveMessage(), got " << fds.size(); + } + return std::move(std::get<base::unique_fd>(fds[0])); + } + void run() { LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!"); std::vector<std::thread> threads; while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) { - base::unique_fd acceptedFd( - TEMP_FAILURE_RETRY(accept4(mFd.fd.get(), nullptr, nullptr /*length*/, - SOCK_CLOEXEC | SOCK_NONBLOCK))); + base::unique_fd acceptedFd = mAcceptConnection(this); threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd)); } @@ -1882,8 +1958,9 @@ public: private: std::unique_ptr<std::thread> mThread; ConnectToServer mConnectToServer; + AcceptConnection mAcceptConnection = &Server::acceptServerConnection; std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make(); - RpcTransportFd mFd; + RpcTransportFd mFd, mBootstrapSocket; std::unique_ptr<RpcTransportCtx> mCtx; std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier = std::make_shared<RpcCertificateVerifierSimple>(); diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index fddf5f35a2..823bbf6b7f 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -49,6 +49,7 @@ #include "../BuildFlags.h" #include "../FdTrigger.h" +#include "../OS.h" // for testing UnixBootstrap clients #include "../RpcSocketAddress.h" // for testing preconnected clients #include "../RpcState.h" // for debugging #include "../vm_sockets.h" // for VMADDR_* @@ -67,15 +68,19 @@ static inline std::vector<RpcSecurity> RpcSecurityValues() { enum class SocketType { PRECONNECTED, UNIX, + UNIX_BOOTSTRAP, VSOCK, INET, }; + static inline std::string PrintToString(SocketType socketType) { switch (socketType) { case SocketType::PRECONNECTED: return "preconnected_uds"; case SocketType::UNIX: return "unix_domain_socket"; + case SocketType::UNIX_BOOTSTRAP: + return "unix_domain_socket_bootstrap"; case SocketType::VSOCK: return "vm_socket"; case SocketType::INET: diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index 31eb5dadf1..a922b21dd7 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -42,6 +42,7 @@ int main(int argc, const char* argv[]) { server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes); unsigned int outPort = 0; + base::unique_fd unixBootstrapFd(serverConfig.unixBootstrapFd); switch (socketType) { case SocketType::PRECONNECTED: @@ -50,6 +51,9 @@ int main(int argc, const char* argv[]) { CHECK_EQ(OK, server->setupUnixDomainServer(serverConfig.addr.c_str())) << serverConfig.addr; break; + case SocketType::UNIX_BOOTSTRAP: + CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd))); + break; case SocketType::VSOCK: CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort)); break; diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 6b3f17e70d..397ff41d58 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -59,4 +59,18 @@ std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() { return RpcTransportCtxFactoryTipcTrusty::make(); } +int sendMessageOnSocket( + const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) { + errno = ENOTSUP; + return -1; +} + +int receiveMessageFromSocket( + const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) { + errno = ENOTSUP; + return -1; +} + } // namespace android |