diff options
Diffstat (limited to 'libs/binder/RpcState.cpp')
-rw-r--r-- | libs/binder/RpcState.cpp | 67 |
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); } |