CVE-2025-48540 AI-generated analysis
platform/frameworks/native, libbinder RPC Binder (libs/binder/RpcState.cpp)
Three small commits to libs/binder/RpcState.cpp make RPC Binder terminate the session (session->shutdownAndWait(false)) on error paths that previously only returned an error code and left the session alive. The paths are: a TRANSACT command received when a non-ANY CommandType was expected; a bad object-table span in an incoming transaction; and CommandData allocation failure in processTransact and waitForReply.
Root cause
RpcState processes a byte stream from a remote peer, and its wire protocol is not self-synchronizing (the existing comment in processCommand says there is no way to tell where one command ends and the next begins). Several error paths detected malformed or unexpected input but only returned a status code (BAD_TYPE, BAD_VALUE, NO_MEMORY) without calling session->shutdownAndWait(false): (1) processCommand received RPC_COMMAND_TRANSACT while the caller requested a CommandType other than ANY, and returned BAD_TYPE before processTransact could read the body; (2) in the incoming-transaction path (processTransactInternalTailCall label), the object-table bytes inferred from parcelDataSize could not be reinterpreted as uint32_t, and the code returned BAD_VALUE; (3) processTransact and waitForReply failed to allocate CommandData for the body and returned NO_MEMORY without reading it. In each case the session continued, so the stream could be left desynchronized. The SPAN commit calls its error return 'not recoverable', and the ENOMEM comment says 'the wire protocol gets messed up'.
How the fix works
- Commit 995eb96a80a2 (RPC Binder: shutdown on SPAN error), libs/binder/RpcState.cpp, transaction path (hunk at the processTransactInternalTailCall label): when objectTableBytes->reinterpret<const uint32_t>() yields no value, it adds (void)session->shutdownAndWait(false) before return BAD_VALUE.
- Commit 71342a41e519 (RPC Binder: clearer errors for wrong transact type), libs/binder/RpcState.cpp:processCommand: in the RPC_COMMAND_TRANSACT case with type != CommandType::ANY, the code now logs ALOGE("CommandType %d, but got RPC command %d.") and calls (void)session->shutdownAndWait(false) before return BAD_TYPE. This mirrors the existing unknown-command handling at the end of processCommand, which already ended the session.
- Commit e73e9de0288c (RPC Binder: shutdown on ENOMEM), libs/binder/RpcState.cpp:waitForReply and libs/binder/RpcState.cpp:processTransact: when CommandData(...).valid() is false, the code calls (void)session->shutdownAndWait(false) before return NO_MEMORY. A comment (b/404210068) explains that the wire protocol gets messed up, because recovering gracefully would mean reading the body and still sending a reply.
- Return codes are unchanged. Only session shutdown (and one log line) is added.
Completeness
- Covered: a wrong-type TRANSACT in processCommand; a bad object-table span in the incoming transaction path; CommandData allocation failure in processTransact and waitForReply.
- The existing size checks in waitForReply (bodySize < rpcReplyWireSize; parcelDataSize larger than the available bytes) already called shutdownAndWait. These commits do not change them.
- Not covered: in waitForReply at android-security-14.0.0_r29 (lines 689-697), the sibling check where objectTableBytes->reinterpret<const uint32_t>() fails on an RpcWireReply still returns BAD_VALUE without session->shutdownAndWait(false), unlike the fixed transaction-side check.
- The ENOMEM commit message says 'More work needs to be done to ignore transactions in out of memory conditions'. The fix ends the session rather than recovering gracefully.
Behavior changes
- An RPC session is now shut down (shutdownAndWait(false)) when a TRANSACT command arrives while a non-ANY CommandType was expected. Before, only BAD_TYPE was returned.
- A new ALOGE line is logged for the wrong-type TRANSACT case.
- The session is shut down when the object-table span of an incoming transaction is malformed. Before, only BAD_VALUE was returned.
- The session is shut down when the body buffer for a transaction or a reply cannot be allocated. Before, only NO_MEMORY was returned. Return codes themselves are unchanged.
Per major
- Android 14: Same fix: three commits (995eb96a80a2, 71342a41e519, e73e9de0288c) landed in android-security-14.0.0_r22. At android-security-14.0.0_r29, 5/5 patched-region lines are present. The shown context confirms the processCommand wrong-type change and the waitForReply ENOMEM change.
- Android 15: Same fix: 7fb4755c9d93 (clearer errors for wrong transact type) in android-security-15.0.0_r10, with an identical hunk at a shifted line (824). 5/6 patched-region lines are present at android-security-15.0.0_r17. The material does not show whether the SPAN and ENOMEM commits are on 15.
- Android 16: Same fix: a9e6d5a3c679 (clearer errors for wrong transact type) in android-security-16.0.0_r1, with an identical hunk at line 827. 5/6 patched-region lines are present at android-security-16.0.0_r8. The material does not show whether the SPAN and ENOMEM commits are on 16.
- Android 17: Not affected per the bulletin. At android-security-17.0.0_r1 only 3/6 patched-region lines match; the material does not show the Android 17 code.
Unknowns
- The exact security consequence (how a desynchronized session leads to the bulletin's EoP) is not shown.
- Whether the SPAN (995eb96a80a2) and ENOMEM (e73e9de0288c) commits were also applied on Android 15 and 16. Only the wrong-type commit is shown for those branches.
- The Android 17 code state (3/6 lines) is not shown.
- The name and signature of the function containing the SPAN hunk; only the processTransactInternalTailCall label is shown.