diff options
-rw-r--r-- | libs/binder/RpcState.cpp | 35 | ||||
-rw-r--r-- | libs/binder/RpcState.h | 19 |
2 files changed, 43 insertions, 11 deletions
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 96190dc03c..976351c6c4 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -326,7 +326,11 @@ status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address .asyncNumber = asyncNumber, }; - std::vector<uint8_t> transactionData(sizeof(RpcWireTransaction) + data.dataSize()); + ByteVec transactionData(sizeof(RpcWireTransaction) + data.dataSize()); + if (!transactionData.valid()) { + return NO_MEMORY; + } + memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction)); memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize()); @@ -379,9 +383,12 @@ status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcSession>& if (status != OK) return status; } - uint8_t* data = new uint8_t[command.bodySize]; + ByteVec data(command.bodySize); + if (!data.valid()) { + return NO_MEMORY; + } - if (!rpcRec(fd, "reply body", data, command.bodySize)) { + if (!rpcRec(fd, "reply body", data.data(), command.bodySize)) { return DEAD_OBJECT; } @@ -391,9 +398,10 @@ status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcSession>& terminate(); return BAD_VALUE; } - RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data); + RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data()); if (rpcReply->status != OK) return rpcReply->status; + data.release(); reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data), nullptr, 0, cleanup_reply_data); @@ -461,7 +469,10 @@ status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcSessio const RpcWireHeader& command) { LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command); - std::vector<uint8_t> transactionData(command.bodySize); + ByteVec transactionData(command.bodySize); + if (!transactionData.valid()) { + return NO_MEMORY; + } if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) { return DEAD_OBJECT; } @@ -479,7 +490,7 @@ static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t d } status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session, - std::vector<uint8_t>&& transactionData) { + ByteVec transactionData) { if (transactionData.size() < sizeof(RpcWireTransaction)) { ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!", sizeof(RpcWireTransaction), transactionData.size()); @@ -630,7 +641,7 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R // justification for const_cast (consider avoiding priority_queue): // - AsyncTodo operator< doesn't depend on 'data' object // - gotta go fast - std::vector<uint8_t> data = std::move( + ByteVec data = std::move( const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data); it->second.asyncTodo.pop(); _l.unlock(); @@ -644,7 +655,10 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R .status = replyStatus, }; - std::vector<uint8_t> replyData(sizeof(RpcWireReply) + reply.dataSize()); + ByteVec replyData(sizeof(RpcWireReply) + reply.dataSize()); + if (!replyData.valid()) { + return NO_MEMORY; + } memcpy(replyData.data() + 0, &rpcReply, sizeof(RpcWireReply)); memcpy(replyData.data() + sizeof(RpcWireReply), reply.data(), reply.dataSize()); @@ -671,7 +685,10 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) { LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command); - std::vector<uint8_t> commandData(command.bodySize); + ByteVec commandData(command.bodySize); + if (!commandData.valid()) { + return NO_MEMORY; + } if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) { return DEAD_OBJECT; } diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index 3f3eb1c2ed..83d034497f 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -21,6 +21,7 @@ #include <binder/RpcSession.h> #include <map> +#include <optional> #include <queue> namespace android { @@ -100,6 +101,20 @@ private: */ void terminate(); + // alternative to std::vector<uint8_t> that doesn't abort on too big of allocations + struct ByteVec { + explicit ByteVec(size_t size) + : mData(size > 0 ? new (std::nothrow) uint8_t[size] : nullptr), mSize(size) {} + bool valid() { return mSize == 0 || mData != nullptr; } + size_t size() { return mSize; } + uint8_t* data() { return mData.get(); } + uint8_t* release() { return mData.release(); } + + private: + std::unique_ptr<uint8_t[]> mData; + size_t mSize; + }; + [[nodiscard]] bool rpcSend(const base::unique_fd& fd, const char* what, const void* data, size_t size); [[nodiscard]] bool rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size); @@ -113,7 +128,7 @@ private: const RpcWireHeader& command); [[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session, - std::vector<uint8_t>&& transactionData); + ByteVec transactionData); [[nodiscard]] status_t processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command); @@ -148,7 +163,7 @@ private: // async transaction queue, _only_ for local binder struct AsyncTodo { - std::vector<uint8_t> data; // most convenient format, to move it here + ByteVec data; uint64_t asyncNumber = 0; bool operator<(const AsyncTodo& o) const { |