summaryrefslogtreecommitdiff
path: root/libs/binder/RpcState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/binder/RpcState.cpp')
-rw-r--r--libs/binder/RpcState.cpp67
1 files changed, 54 insertions, 13 deletions
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index f5de5b1eaf..419df86a4c 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -27,6 +27,7 @@
#include "Debug.h"
#include "RpcWireFormat.h"
+#include "Utils.h"
#include <random>
@@ -493,9 +494,15 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti
}
}
+ // objectTable always empty for now. Will be populated from `data` soon.
+ std::vector<uint32_t> objectTable;
+ Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};
+
uint32_t bodySize;
LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireTransaction), data.dataSize(),
- &bodySize),
+ &bodySize) ||
+ __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+ &bodySize),
"Too much data %zu", data.dataSize());
RpcWireHeader command{
.command = RPC_COMMAND_TRANSACT,
@@ -507,6 +514,8 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti
.code = code,
.flags = flags,
.asyncNumber = asyncNumber,
+ // bodySize didn't overflow => this cast is safe
+ .parcelDataSize = static_cast<uint32_t>(data.dataSize()),
};
constexpr size_t kWaitMaxUs = 1000000;
@@ -521,6 +530,7 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti
{&command, sizeof(RpcWireHeader)},
{&transaction, sizeof(RpcWireTransaction)},
{const_cast<uint8_t*>(data.data()), data.dataSize()},
+ objectTableSpan.toIovec(),
};
if (status_t status = rpcSend(connection, session, "transaction", iovs, arraysize(iovs),
[&] {
@@ -585,7 +595,9 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
return status;
}
- if (command.bodySize < sizeof(RpcWireReply)) {
+ const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
+
+ if (command.bodySize < rpcReplyWireSize) {
ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
sizeof(RpcWireReply), command.bodySize);
(void)session->shutdownAndWait(false);
@@ -593,11 +605,13 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
}
RpcWireReply rpcReply;
- CommandData data(command.bodySize - sizeof(RpcWireReply));
+ memset(&rpcReply, 0, sizeof(RpcWireReply)); // zero because of potential short read
+
+ CommandData data(command.bodySize - rpcReplyWireSize);
if (!data.valid()) return NO_MEMORY;
iovec iovs[]{
- {&rpcReply, sizeof(RpcWireReply)},
+ {&rpcReply, rpcReplyWireSize},
{data.data(), data.size()},
};
if (status_t status = rpcRec(connection, session, "reply body", iovs, arraysize(iovs));
@@ -605,11 +619,15 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
return status;
if (rpcReply.status != OK) return rpcReply.status;
- uint8_t* parcelData = data.data();
- size_t parcelDataSize = data.size();
- data.release();
- reply->rpcSetDataReference(session, parcelData, parcelDataSize, cleanup_reply_data);
+ Span<const uint8_t> parcelSpan = {data.data(), data.size()};
+ if (session->getProtocolVersion().value() >=
+ RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+ Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+ LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0, "Non-empty object table not supported yet.");
+ }
+ data.release();
+ reply->rpcSetDataReference(session, parcelSpan.data, parcelSpan.size, cleanup_reply_data);
return OK;
}
@@ -824,12 +842,22 @@ processTransactInternalTailCall:
reply.markForRpc(session);
if (replyStatus == OK) {
+ Span<const uint8_t> parcelSpan = {transaction->data,
+ transactionData.size() -
+ offsetof(RpcWireTransaction, data)};
+ if (session->getProtocolVersion().value() >=
+ RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
+ Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+ LOG_ALWAYS_FATAL_IF(objectTableBytes.size > 0,
+ "Non-empty object table not supported yet.");
+ }
+
Parcel data;
// transaction->data is owned by this function. Parcel borrows this data and
// only holds onto it for the duration of this function call. Parcel will be
// deleted before the 'transactionData' object.
- data.rpcSetDataReference(session, transaction->data,
- transactionData.size() - offsetof(RpcWireTransaction, data),
+
+ data.rpcSetDataReference(session, parcelSpan.data, parcelSpan.size,
do_nothing_to_transact_data);
if (target) {
@@ -941,8 +969,16 @@ processTransactInternalTailCall:
replyStatus = flushExcessBinderRefs(session, addr, target);
}
+ const size_t rpcReplyWireSize = RpcWireReply::wireSize(session->getProtocolVersion().value());
+
+ // objectTable always empty for now. Will be populated from `reply` soon.
+ std::vector<uint32_t> objectTable;
+ Span<const uint32_t> objectTableSpan = {objectTable.data(), objectTable.size()};
+
uint32_t bodySize;
- LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(sizeof(RpcWireReply), reply.dataSize(), &bodySize),
+ LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(rpcReplyWireSize, reply.dataSize(), &bodySize) ||
+ __builtin_add_overflow(objectTableSpan.byteSize(), bodySize,
+ &bodySize),
"Too much data for reply %zu", reply.dataSize());
RpcWireHeader cmdReply{
.command = RPC_COMMAND_REPLY,
@@ -950,12 +986,17 @@ processTransactInternalTailCall:
};
RpcWireReply rpcReply{
.status = replyStatus,
+ // NOTE: Not necessarily written to socket depending on session
+ // version.
+ // NOTE: bodySize didn't overflow => this cast is safe
+ .parcelDataSize = static_cast<uint32_t>(reply.dataSize()),
+ .reserved = {0, 0, 0},
};
-
iovec iovs[]{
{&cmdReply, sizeof(RpcWireHeader)},
- {&rpcReply, sizeof(RpcWireReply)},
+ {&rpcReply, rpcReplyWireSize},
{const_cast<uint8_t*>(reply.data()), reply.dataSize()},
+ objectTableSpan.toIovec(),
};
return rpcSend(connection, session, "reply", iovs, arraysize(iovs), std::nullopt);
}