libbinder: add ancillaryFd support in RpcTransportTipcTrusty
Implement ParcelFileDescriptor support in Trusty by
adding support for ancillaryFd to RpcTransportTipcTrusty.
Bug: 242940548
Test: Trusty tests
Change-Id: Ic5602bbf9f239f65489e0f411f89b10907741be3
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 8333298..07d0a65 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1439,7 +1439,8 @@
case RpcSession::FileDescriptorTransportMode::NONE: {
return FDS_NOT_ALLOWED;
}
- case RpcSession::FileDescriptorTransportMode::UNIX: {
+ case RpcSession::FileDescriptorTransportMode::UNIX:
+ case RpcSession::FileDescriptorTransportMode::TRUSTY: {
if (rpcFields->mFds == nullptr) {
rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index c411f4f..4d48309 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -56,6 +56,7 @@
case RpcSession::FileDescriptorTransportMode::NONE:
return false;
case RpcSession::FileDescriptorTransportMode::UNIX:
+ case RpcSession::FileDescriptorTransportMode::TRUSTY:
return true;
}
}
@@ -1205,6 +1206,20 @@
rpcFields->mFds->size(), kMaxFdsPerMsg);
return BAD_VALUE;
}
+ break;
+ }
+ case RpcSession::FileDescriptorTransportMode::TRUSTY: {
+ // Keep this in sync with trusty_ipc.h!!!
+ // We could import that file here on Trusty, but it's not
+ // available on Android
+ constexpr size_t kMaxFdsPerMsg = 8;
+ if (rpcFields->mFds->size() > kMaxFdsPerMsg) {
+ *errorMsg = StringPrintf("Too many file descriptors in Parcel for Trusty "
+ "IPC connection: %zu (max is %zu)",
+ rpcFields->mFds->size(), kMaxFdsPerMsg);
+ return BAD_VALUE;
+ }
+ break;
}
}
}
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index a25ba98..1bd4975 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -100,6 +100,8 @@
NONE = 0,
// Send file descriptors via unix domain socket ancillary data.
UNIX = 1,
+ // Send file descriptors as Trusty IPC handles.
+ TRUSTY = 2,
};
/**
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 46346bb..6b3f17e 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -16,6 +16,7 @@
#if defined(TRUSTY_USERSPACE)
#include <openssl/rand.h>
+#include <trusty_ipc.h>
#else
#include <lib/rand/rand.h>
#endif
@@ -23,6 +24,7 @@
#include <binder/RpcTransportTipcTrusty.h>
#include "../OS.h"
+#include "TrustyStatus.h"
using android::base::Result;
@@ -43,9 +45,14 @@
#endif // TRUSTY_USERSPACE
}
-status_t dupFileDescriptor(int /*oldFd*/, int* /*newFd*/) {
- // TODO: implement separately
- return INVALID_OPERATION;
+status_t dupFileDescriptor(int oldFd, int* newFd) {
+ int res = dup(oldFd);
+ if (res < 0) {
+ return statusFromTrusty(res);
+ }
+
+ *newFd = res;
+ return OK;
}
std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() {
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index 0b67b9f..58bfe71 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "RpcTransportTipcTrusty"
+#include <inttypes.h>
#include <trusty_ipc.h>
#include <binder/RpcSession.h>
@@ -47,7 +48,7 @@
status_t interruptableWriteFully(
FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
- const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
override {
if (niovs < 0) {
return BAD_VALUE;
@@ -58,12 +59,32 @@
size += iovs[i].iov_len;
}
+ handle_t msgHandles[IPC_MAX_MSG_HANDLES];
ipc_msg_t msg{
.num_iov = static_cast<uint32_t>(niovs),
.iov = iovs,
- .num_handles = 0, // TODO: add ancillaryFds
+ .num_handles = 0,
.handles = nullptr,
};
+
+ if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
+ if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) {
+ // This shouldn't happen because we check the FD count in RpcState.
+ ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: "
+ "%zu (max is %u). Aborting session.",
+ ancillaryFds->size(), IPC_MAX_MSG_HANDLES);
+ return BAD_VALUE;
+ }
+
+ for (size_t i = 0; i < ancillaryFds->size(); i++) {
+ msgHandles[i] =
+ std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
+ }
+
+ msg.num_handles = ancillaryFds->size();
+ msg.handles = msgHandles;
+ }
+
ssize_t rc = send_msg(mSocket.fd.get(), &msg);
if (rc == ERR_NOT_ENOUGH_BUFFER) {
// Peer is blocked, wait until it unblocks.
@@ -97,8 +118,7 @@
status_t interruptableReadFully(
FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
- std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
- override {
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
if (niovs < 0) {
return BAD_VALUE;
}
@@ -124,11 +144,16 @@
return status;
}
+ LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES,
+ "Received too many handles %" PRIu32, mMessageInfo.num_handles);
+ bool haveHandles = mMessageInfo.num_handles != 0;
+ handle_t msgHandles[IPC_MAX_MSG_HANDLES];
+
ipc_msg_t msg{
.num_iov = static_cast<uint32_t>(niovs),
.iov = iovs,
- .num_handles = 0, // TODO: support ancillaryFds
- .handles = nullptr,
+ .num_handles = mMessageInfo.num_handles,
+ .handles = haveHandles ? msgHandles : 0,
};
ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
if (rc < 0) {
@@ -141,6 +166,28 @@
"Message offset exceeds length %zu/%zu", mMessageOffset,
mMessageInfo.len);
+ if (haveHandles) {
+ if (ancillaryFds != nullptr) {
+ ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles);
+ for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
+ ancillaryFds->emplace_back(base::unique_fd(msgHandles[i]));
+ }
+
+ // Clear the saved number of handles so we don't accidentally
+ // read them multiple times
+ mMessageInfo.num_handles = 0;
+ haveHandles = false;
+ } else {
+ ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles);
+ // It should be safe to continue here. We could abort, but then
+ // peers could DoS us by sending messages with handles in them.
+ // Close the handles since we are ignoring them.
+ for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
+ ::close(msgHandles[i]);
+ }
+ }
+ }
+
// Release the message if all of it has been read
if (mMessageOffset == mMessageInfo.len) {
releaseMessage();
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index cc31c95..7d9dd8c 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -60,6 +60,10 @@
std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); }
+ void setSupportedFileDescriptorTransportModes(
+ const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
+ mRpcServer->setSupportedFileDescriptorTransportModes(modes);
+ }
void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); }
void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); }
void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) {