diff options
Diffstat (limited to 'libs/binder/RpcState.cpp')
| -rw-r--r-- | libs/binder/RpcState.cpp | 237 |
1 files changed, 132 insertions, 105 deletions
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 6483486340..a8017296fa 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -207,45 +207,49 @@ RpcState::CommandData::CommandData(size_t size) : mSize(size) { mData.reset(new (std::nothrow) uint8_t[size]); } -bool RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* data, size_t size) { +status_t RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* data, + size_t size) { LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str()); if (size > std::numeric_limits<ssize_t>::max()) { ALOGE("Cannot send %s at size %zu (too big)", what, size); terminate(); - return false; + return BAD_VALUE; } ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, MSG_NOSIGNAL)); if (sent < 0 || sent != static_cast<ssize_t>(size)) { + int savedErrno = errno; ALOGE("Failed to send %s (sent %zd of %zu bytes) on fd %d, error: %s", what, sent, size, - fd.get(), strerror(errno)); + fd.get(), strerror(savedErrno)); terminate(); - return false; + return -savedErrno; } - return true; + return OK; } -bool RpcState::rpcRec(const base::unique_fd& fd, const sp<RpcSession>& session, const char* what, - void* data, size_t size) { +status_t RpcState::rpcRec(const base::unique_fd& fd, const sp<RpcSession>& session, + const char* what, void* data, size_t size) { if (size > std::numeric_limits<ssize_t>::max()) { ALOGE("Cannot rec %s at size %zu (too big)", what, size); terminate(); - return false; + return BAD_VALUE; } if (status_t status = session->mShutdownTrigger->interruptableReadFully(fd.get(), data, size); status != OK) { - ALOGE("Failed to read %s (%zu bytes) on fd %d, error: %s", what, size, fd.get(), - statusToString(status).c_str()); - return false; + if (status != -ECANCELED) { + ALOGE("Failed to read %s (%zu bytes) on fd %d, error: %s", what, size, fd.get(), + statusToString(status).c_str()); + } + return status; } LOG_RPC_DETAIL("Received %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str()); - return true; + return OK; } sp<IBinder> RpcState::getRootObject(const base::unique_fd& fd, const sp<RpcSession>& session) { @@ -253,8 +257,8 @@ sp<IBinder> RpcState::getRootObject(const base::unique_fd& fd, const sp<RpcSessi data.markForRpc(session); Parcel reply; - status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT, data, session, - &reply, 0); + status_t status = transactAddress(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT, data, + session, &reply, 0); if (status != OK) { ALOGE("Error getting root object: %s", statusToString(status).c_str()); return nullptr; @@ -269,8 +273,8 @@ status_t RpcState::getMaxThreads(const base::unique_fd& fd, const sp<RpcSession> data.markForRpc(session); Parcel reply; - status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data, - session, &reply, 0); + status_t status = transactAddress(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, + data, session, &reply, 0); if (status != OK) { ALOGE("Error getting max threads: %s", statusToString(status).c_str()); return status; @@ -294,8 +298,8 @@ status_t RpcState::getSessionId(const base::unique_fd& fd, const sp<RpcSession>& data.markForRpc(session); Parcel reply; - status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_SESSION_ID, data, - session, &reply, 0); + status_t status = transactAddress(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_SESSION_ID, + data, session, &reply, 0); if (status != OK) { ALOGE("Error getting session ID: %s", statusToString(status).c_str()); return status; @@ -309,9 +313,31 @@ status_t RpcState::getSessionId(const base::unique_fd& fd, const sp<RpcSession>& return OK; } -status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address, uint32_t code, +status_t RpcState::transact(const base::unique_fd& fd, const sp<IBinder>& binder, uint32_t code, const Parcel& data, const sp<RpcSession>& session, Parcel* reply, uint32_t flags) { + if (!data.isForRpc()) { + ALOGE("Refusing to send RPC with parcel not crafted for RPC"); + return BAD_TYPE; + } + + if (data.objectsCount() != 0) { + ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data); + return BAD_TYPE; + } + + RpcAddress address = RpcAddress::zero(); + if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status; + + return transactAddress(fd, address, code, data, session, reply, flags); +} + +status_t RpcState::transactAddress(const base::unique_fd& fd, const RpcAddress& address, + uint32_t code, const Parcel& data, const sp<RpcSession>& session, + Parcel* reply, uint32_t flags) { + LOG_ALWAYS_FATAL_IF(!data.isForRpc()); + LOG_ALWAYS_FATAL_IF(data.objectsCount() != 0); + uint64_t asyncNumber = 0; if (!address.isZero()) { @@ -326,16 +352,6 @@ status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address } } - if (!data.isForRpc()) { - ALOGE("Refusing to send RPC with parcel not crafted for RPC"); - return BAD_TYPE; - } - - if (data.objectsCount() != 0) { - ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data); - return BAD_TYPE; - } - RpcWireTransaction transaction{ .address = address.viewRawEmbedded(), .code = code, @@ -361,12 +377,12 @@ status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address .bodySize = static_cast<uint32_t>(transactionData.size()), }; - if (!rpcSend(fd, "transact header", &command, sizeof(command))) { - return DEAD_OBJECT; - } - if (!rpcSend(fd, "command body", transactionData.data(), transactionData.size())) { - return DEAD_OBJECT; - } + if (status_t status = rpcSend(fd, "transact header", &command, sizeof(command)); status != OK) + return status; + if (status_t status = + rpcSend(fd, "command body", transactionData.data(), transactionData.size()); + status != OK) + return status; if (flags & IBinder::FLAG_ONEWAY) { return OK; // do not wait for result @@ -390,24 +406,22 @@ status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcSession>& Parcel* reply) { RpcWireHeader command; while (true) { - if (!rpcRec(fd, session, "command header", &command, sizeof(command))) { - return DEAD_OBJECT; - } + if (status_t status = rpcRec(fd, session, "command header", &command, sizeof(command)); + status != OK) + return status; if (command.command == RPC_COMMAND_REPLY) break; - status_t status = processServerCommand(fd, session, command); - if (status != OK) return status; + if (status_t status = processServerCommand(fd, session, command); status != OK) + return status; } CommandData data(command.bodySize); - if (!data.valid()) { - return NO_MEMORY; - } + if (!data.valid()) return NO_MEMORY; - if (!rpcRec(fd, session, "reply body", data.data(), command.bodySize)) { - return DEAD_OBJECT; - } + if (status_t status = rpcRec(fd, session, "reply body", data.data(), command.bodySize); + status != OK) + return status; if (command.bodySize < sizeof(RpcWireReply)) { ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!", @@ -447,9 +461,12 @@ status_t RpcState::sendDecStrong(const base::unique_fd& fd, const RpcAddress& ad .command = RPC_COMMAND_DEC_STRONG, .bodySize = sizeof(RpcWireAddress), }; - if (!rpcSend(fd, "dec ref header", &cmd, sizeof(cmd))) return DEAD_OBJECT; - if (!rpcSend(fd, "dec ref body", &addr.viewRawEmbedded(), sizeof(RpcWireAddress))) - return DEAD_OBJECT; + if (status_t status = rpcSend(fd, "dec ref header", &cmd, sizeof(cmd)); status != OK) + return status; + if (status_t status = + rpcSend(fd, "dec ref body", &addr.viewRawEmbedded(), sizeof(RpcWireAddress)); + status != OK) + return status; return OK; } @@ -457,9 +474,9 @@ status_t RpcState::getAndExecuteCommand(const base::unique_fd& fd, const sp<RpcS LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", fd.get()); RpcWireHeader command; - if (!rpcRec(fd, session, "command header", &command, sizeof(command))) { - return DEAD_OBJECT; - } + if (status_t status = rpcRec(fd, session, "command header", &command, sizeof(command)); + status != OK) + return status; return processServerCommand(fd, session, command); } @@ -505,11 +522,12 @@ status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcSessio if (!transactionData.valid()) { return NO_MEMORY; } - if (!rpcRec(fd, session, "transaction body", transactionData.data(), transactionData.size())) { - return DEAD_OBJECT; - } + if (status_t status = rpcRec(fd, session, "transaction body", transactionData.data(), + transactionData.size()); + status != OK) + return status; - return processTransactInternal(fd, session, std::move(transactionData)); + return processTransactInternal(fd, session, std::move(transactionData), nullptr /*targetRef*/); } static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize, @@ -522,7 +540,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, - CommandData transactionData) { + CommandData transactionData, sp<IBinder>&& targetRef) { if (transactionData.size() < sizeof(RpcWireTransaction)) { ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!", sizeof(RpcWireTransaction), transactionData.size()); @@ -538,45 +556,49 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R status_t replyStatus = OK; sp<IBinder> target; if (!addr.isZero()) { - std::lock_guard<std::mutex> _l(mNodeMutex); + if (!targetRef) { + target = onBinderEntering(session, addr); + } else { + target = targetRef; + } - auto it = mNodeForAddress.find(addr); - if (it == mNodeForAddress.end()) { - ALOGE("Unknown binder address %s.", addr.toString().c_str()); + if (target == nullptr) { + // This can happen if the binder is remote in this process, and + // another thread has called the last decStrong on this binder. + // However, for local binders, it indicates a misbehaving client + // (any binder which is being transacted on should be holding a + // strong ref count), so in either case, terminating the + // session. + ALOGE("While transacting, binder has been deleted at address %s. Terminating!", + addr.toString().c_str()); + terminate(); replyStatus = BAD_VALUE; - } else { - target = it->second.binder.promote(); - if (target == nullptr) { - // This can happen if the binder is remote in this process, and - // another thread has called the last decStrong on this binder. - // However, for local binders, it indicates a misbehaving client - // (any binder which is being transacted on should be holding a - // strong ref count), so in either case, terminating the - // session. - ALOGE("While transacting, binder has been deleted at address %s. Terminating!", - addr.toString().c_str()); - terminate(); - replyStatus = BAD_VALUE; - } else if (target->localBinder() == nullptr) { - ALOGE("Transactions can only go to local binders, not address %s. Terminating!", + } else if (target->localBinder() == nullptr) { + ALOGE("Unknown binder address or non-local binder, not address %s. Terminating!", + addr.toString().c_str()); + terminate(); + replyStatus = BAD_VALUE; + } else if (transaction->flags & IBinder::FLAG_ONEWAY) { + std::lock_guard<std::mutex> _l(mNodeMutex); + auto it = mNodeForAddress.find(addr); + if (it->second.binder.promote() != target) { + ALOGE("Binder became invalid during transaction. Bad client? %s", addr.toString().c_str()); - terminate(); replyStatus = BAD_VALUE; - } else if (transaction->flags & IBinder::FLAG_ONEWAY) { - if (transaction->asyncNumber != it->second.asyncNumber) { - // we need to process some other asynchronous transaction - // first - // TODO(b/183140903): limit enqueues/detect overfill for bad client - // TODO(b/183140903): detect when an object is deleted when it still has - // pending async transactions - it->second.asyncTodo.push(BinderNode::AsyncTodo{ - .data = std::move(transactionData), - .asyncNumber = transaction->asyncNumber, - }); - LOG_RPC_DETAIL("Enqueuing %" PRId64 " on %s", transaction->asyncNumber, - addr.toString().c_str()); - return OK; - } + } else if (transaction->asyncNumber != it->second.asyncNumber) { + // we need to process some other asynchronous transaction + // first + // TODO(b/183140903): limit enqueues/detect overfill for bad client + // TODO(b/183140903): detect when an object is deleted when it still has + // pending async transactions + it->second.asyncTodo.push(BinderNode::AsyncTodo{ + .ref = target, + .data = std::move(transactionData), + .asyncNumber = transaction->asyncNumber, + }); + LOG_RPC_DETAIL("Enqueuing %" PRId64 " on %s", transaction->asyncNumber, + addr.toString().c_str()); + return OK; } } } @@ -670,13 +692,17 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R it->second.asyncNumber, addr.toString().c_str()); // justification for const_cast (consider avoiding priority_queue): - // - AsyncTodo operator< doesn't depend on 'data' object + // - AsyncTodo operator< doesn't depend on 'data' or 'ref' objects // - gotta go fast - CommandData data = std::move( - const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data); + auto& todo = const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()); + + CommandData nextData = std::move(todo.data); + sp<IBinder> nextRef = std::move(todo.ref); + it->second.asyncTodo.pop(); _l.unlock(); - return processTransactInternal(fd, session, std::move(data)); + return processTransactInternal(fd, session, std::move(nextData), + std::move(nextRef)); } } return OK; @@ -704,12 +730,12 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<R .bodySize = static_cast<uint32_t>(replyData.size()), }; - if (!rpcSend(fd, "reply header", &cmdReply, sizeof(RpcWireHeader))) { - return DEAD_OBJECT; - } - if (!rpcSend(fd, "reply body", replyData.data(), replyData.size())) { - return DEAD_OBJECT; - } + if (status_t status = rpcSend(fd, "reply header", &cmdReply, sizeof(RpcWireHeader)); + status != OK) + return status; + if (status_t status = rpcSend(fd, "reply body", replyData.data(), replyData.size()); + status != OK) + return status; return OK; } @@ -721,9 +747,10 @@ status_t RpcState::processDecStrong(const base::unique_fd& fd, const sp<RpcSessi if (!commandData.valid()) { return NO_MEMORY; } - if (!rpcRec(fd, session, "dec ref body", commandData.data(), commandData.size())) { - return DEAD_OBJECT; - } + if (status_t status = + rpcRec(fd, session, "dec ref body", commandData.data(), commandData.size()); + status != OK) + return status; if (command.bodySize < sizeof(RpcWireAddress)) { ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!", |