summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2021-08-11 17:29:28 -0700
committerYifan Hong <elsk@google.com>2021-08-23 13:58:26 -0700
commitecf937dd80999d2b37c5b44cda1065bfd4da42fb (patch)
tree6526b821f061ed460b7013e54e515c31ff303cd6
parent588d59c6ae1abcad5012d33b15bf4a064315f9ee (diff)
downloadnative-ecf937dd80999d2b37c5b44cda1065bfd4da42fb.tar.gz
binder: RpcServer / RpcSession add API for certs.
These APIs call into RpcTransportCtx::getCertificate and RpcTransportClientCtx::addTrustedPeerCertificate, respectively. For RpcSession, peer (server) certificates are fixed when it is constructed. Test: binderRpcTest Bug: 195166979 Change-Id: I0d1bd93042895aeb3ab1de4fe6b9d90e73d0d116
-rw-r--r--libs/binder/RpcServer.cpp26
-rw-r--r--libs/binder/RpcSession.cpp47
-rw-r--r--libs/binder/include/binder/RpcServer.h16
-rw-r--r--libs/binder/include/binder/RpcSession.h20
-rw-r--r--libs/binder/tests/binderRpcTest.cpp6
-rw-r--r--libs/binder/tests/parcel_fuzzer/random_parcel.cpp3
6 files changed, 80 insertions, 38 deletions
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index a20445b7d7..ad9ba9660f 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -39,8 +39,7 @@ namespace android {
using base::ScopeGuard;
using base::unique_fd;
-RpcServer::RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
- : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {}
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
RpcServer::~RpcServer() {
(void)shutdown();
}
@@ -49,7 +48,9 @@ sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTranspo
// Default is without TLS.
if (rpcTransportCtxFactory == nullptr)
rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
- return sp<RpcServer>::make(std::move(rpcTransportCtxFactory));
+ auto ctx = rpcTransportCtxFactory->newServerCtx();
+ if (ctx == nullptr) return nullptr;
+ return sp<RpcServer>::make(std::move(ctx));
}
void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
@@ -138,6 +139,20 @@ sp<IBinder> RpcServer::getRootObject() {
return ret;
}
+std::string RpcServer::getCertificate(CertificateFormat format) {
+ std::lock_guard<std::mutex> _l(mLock);
+ return mCtx->getCertificate(format);
+}
+
+status_t RpcServer::addTrustedPeerCertificate(CertificateFormat format, std::string_view cert) {
+ std::lock_guard<std::mutex> _l(mLock);
+ // Ensure that join thread is not running or shutdown trigger is not set up. In either case,
+ // it means there are child threads running. It is invalid to add trusted peer certificates
+ // after join thread and/or child threads are running to avoid race condition.
+ if (mJoinThreadRunning || mShutdownTrigger != nullptr) return INVALID_OPERATION;
+ return mCtx->addTrustedPeerCertificate(format, cert);
+}
+
static void joinRpcServer(sp<RpcServer>&& thiz) {
thiz->join();
}
@@ -159,10 +174,6 @@ void RpcServer::join() {
mJoinThreadRunning = true;
mShutdownTrigger = FdTrigger::make();
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
-
- mCtx = mRpcTransportCtxFactory->newServerCtx();
- LOG_ALWAYS_FATAL_IF(mCtx == nullptr, "Unable to create RpcTransportCtx with %s sockets",
- mRpcTransportCtxFactory->toCString());
}
status_t status;
@@ -229,7 +240,6 @@ bool RpcServer::shutdown() {
LOG_RPC_DETAIL("Finished waiting on shutdown.");
mShutdownTrigger = nullptr;
- mCtx = nullptr;
return true;
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 4c47005c7a..22a7782947 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -49,8 +49,7 @@ namespace android {
using base::unique_fd;
-RpcSession::RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
- : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {
LOG_RPC_DETAIL("RpcSession created %p", this);
mState = std::make_unique<RpcState>();
@@ -63,11 +62,26 @@ RpcSession::~RpcSession() {
"Should not be able to destroy a session with servers in use.");
}
-sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+sp<RpcSession> RpcSession::make() {
// Default is without TLS.
- if (rpcTransportCtxFactory == nullptr)
- rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
- return sp<RpcSession>::make(std::move(rpcTransportCtxFactory));
+ return make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+}
+
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
+ std::optional<CertificateFormat> serverCertificateFormat,
+ std::optional<std::string> serverCertificate) {
+ auto ctx = rpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) return nullptr;
+ LOG_ALWAYS_FATAL_IF(serverCertificateFormat.has_value() != serverCertificate.has_value());
+ if (serverCertificateFormat.has_value() && serverCertificate.has_value()) {
+ status_t status =
+ ctx->addTrustedPeerCertificate(*serverCertificateFormat, *serverCertificate);
+ if (status != OK) {
+ ALOGE("Cannot add trusted server certificate: %s", statusToString(status).c_str());
+ return nullptr;
+ }
+ }
+ return sp<RpcSession>::make(std::move(ctx));
}
void RpcSession::setMaxThreads(size_t threads) {
@@ -155,12 +169,7 @@ status_t RpcSession::addNullDebuggingClient() {
return -savedErrno;
}
- auto ctx = mRpcTransportCtxFactory->newClientCtx();
- if (ctx == nullptr) {
- ALOGE("Unable to create RpcTransportCtx for null debugging client");
- return NO_MEMORY;
- }
- auto server = ctx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+ auto server = mCtx->newTransport(std::move(serverFd), mShutdownTrigger.get());
if (server == nullptr) {
ALOGE("Unable to set up RpcTransport");
return UNKNOWN_ERROR;
@@ -529,15 +538,9 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
bool incoming) {
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
- auto ctx = mRpcTransportCtxFactory->newClientCtx();
- if (ctx == nullptr) {
- ALOGE("Unable to create client RpcTransportCtx with %s sockets",
- mRpcTransportCtxFactory->toCString());
- return NO_MEMORY;
- }
- auto server = ctx->newTransport(std::move(fd), mShutdownTrigger.get());
+ auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
if (server == nullptr) {
- ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+ ALOGE("%s: Unable to set up RpcTransport", __PRETTY_FUNCTION__);
return UNKNOWN_ERROR;
}
@@ -692,6 +695,10 @@ bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
return false;
}
+std::string RpcSession::getCertificate(CertificateFormat format) {
+ return mCtx->getCertificate(format);
+}
+
status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, ConnectionUse use,
ExclusiveConnection* connection) {
connection->mSession = session;
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index bf3e7e07f5..d0e4e27c96 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -134,6 +134,17 @@ public:
sp<IBinder> getRootObject();
/**
+ * See RpcTransportCtx::getCertificate
+ */
+ std::string getCertificate(CertificateFormat);
+
+ /**
+ * See RpcTransportCtx::addTrustedPeerCertificate.
+ * Thread-safe. This is only possible before the server is join()-ing.
+ */
+ status_t addTrustedPeerCertificate(CertificateFormat, std::string_view cert);
+
+ /**
* Runs join() in a background thread. Immediately returns.
*/
void start();
@@ -170,7 +181,7 @@ public:
private:
friend sp<RpcServer>;
- explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+ explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
@@ -178,7 +189,7 @@ private:
static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
status_t setupSocketServer(const RpcSocketAddress& address);
- const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+ const std::unique_ptr<RpcTransportCtx> mCtx;
bool mAgreedExperimental = false;
size_t mMaxThreads = 1;
std::optional<uint32_t> mProtocolVersion;
@@ -193,7 +204,6 @@ private:
std::map<RpcAddress, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
- std::unique_ptr<RpcTransportCtx> mCtx;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 6e6eb74668..d92af0a91b 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -51,8 +51,15 @@ constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIM
*/
class RpcSession final : public virtual RefBase {
public:
- static sp<RpcSession> make(
- std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
+ // Create an RpcSession with default configuration (raw sockets).
+ static sp<RpcSession> make();
+
+ // Create an RpcSession with the given configuration. |serverCertificateFormat| and
+ // |serverCertificate| must have values or be nullopt simultaneously. If they have values, set
+ // server certificate.
+ static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
+ std::optional<CertificateFormat> serverCertificateFormat,
+ std::optional<std::string> serverCertificate);
/**
* Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -125,6 +132,11 @@ public:
status_t getRemoteMaxThreads(size_t* maxThreads);
/**
+ * See RpcTransportCtx::getCertificate
+ */
+ std::string getCertificate(CertificateFormat);
+
+ /**
* Shuts down the service.
*
* For client sessions, wait can be true or false. For server sessions,
@@ -159,7 +171,7 @@ private:
friend sp<RpcSession>;
friend RpcServer;
friend RpcState;
- explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+ explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
class EventListener : public virtual RefBase {
public:
@@ -259,7 +271,7 @@ private:
bool mReentrant = false;
};
- const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+ const std::unique_ptr<RpcTransportCtx> mCtx;
// On the other side of a session, for each of mOutgoingConnections here, there should
// be one of mIncomingConnections on the other side (and vice versa).
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 35db4444d5..7c405d3541 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -522,7 +522,8 @@ public:
status_t status;
for (size_t i = 0; i < options.numSessions; i++) {
- sp<RpcSession> session = RpcSession::make(newFactory(rpcSecurity));
+ sp<RpcSession> session =
+ RpcSession::make(newFactory(rpcSecurity), std::nullopt, std::nullopt);
session->setMaxThreads(options.numIncomingConnections);
switch (socketType) {
@@ -1207,7 +1208,8 @@ static bool testSupportVsockLoopback() {
}
server->start();
- sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ sp<RpcSession> session =
+ RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 8bf04ccae0..7fd9f6bb63 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -36,7 +36,8 @@ private:
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
if (provider.ConsumeBool()) {
- auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ auto session =
+ RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
fillRandomParcelData(p, std::move(provider));