* [PATCH] rust_binder: push BR_TRANSACTION_COMPLETE before BR_FAILED_REPLY
@ 2026-10-28 9:46 Alice Ryhl
0 siblings, 0 replies; only message in thread
From: Alice Ryhl @ 2026-10-28 9:46 UTC (permalink / raw)
To: Greg Kroah-Hartman, Carlos Llamas
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, rust-for-linux, linux-kernel,
stable
When building a reply fails in Thread::reply_inner(), BR_FAILED_REPLY is
delivered to the caller before BR_TRANSACTION_COMPLETE is pushed to the
replying thread's work list.
In a nested transaction, the caller can wake up upon receiving
BR_FAILED_REPLY and send an outer reply to the replying thread before
BR_TRANSACTION_COMPLETE is queued. This causes the outer BR_REPLY to
arrive ahead of BR_TRANSACTION_COMPLETE, which is not legal. This leads
to userspace tripping on an assertion.
Thus, push BR_TRANSACTION_COMPLETE in Thread::reply_inner() before
delivering BR_FAILED_REPLY to the caller.
As a nice side effect, this lets us remove the now-unused
BR_TRANSACTION_COMPLETE error path in Thread::transaction().
Cc: stable@vger.kernel.org
Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver")
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
drivers/android/binder/error.rs | 1 -
drivers/android/binder/thread.rs | 33 +++++++++++++--------------------
2 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/drivers/android/binder/error.rs b/drivers/android/binder/error.rs
index 89077c5baeaf..acf0aa09c555 100644
--- a/drivers/android/binder/error.rs
+++ b/drivers/android/binder/error.rs
@@ -114,7 +114,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
BR_DEAD_REPLY => f.pad("BR_DEAD_REPLY"),
BR_FROZEN_REPLY => f.pad("BR_FROZEN_REPLY"),
BR_TRANSACTION_PENDING_FROZEN => f.pad("BR_TRANSACTION_PENDING_FROZEN"),
- BR_TRANSACTION_COMPLETE => f.pad("BR_TRANSACTION_COMPLETE"),
_ => match self.source.as_ref() {
Some(source) => source.fmt(f),
None => self.reply.fmt(f),
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index f5965e838a96..4ce6fc533203 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -1332,20 +1332,16 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
self.transaction_inner(&mut info)
};
- // This runs when return work is passed to the caller. This is not
- // always the same as the transaction failing, as reply errors are
- // delivered to the remote process.
+ // This runs when a transaction fails with an error returned to the caller.
if let Err(err) = ret {
self.push_return_work(err.reply);
- if err.reply != BR_TRANSACTION_COMPLETE {
- info.reply = err.reply;
- info.error_line = Some(err.line);
- if let Some(source) = err.source {
- info.errno = Some(source);
-
- self.inner.lock().extended_error =
- ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
- }
+ info.reply = err.reply;
+ info.error_line = Some(err.line);
+ if let Some(source) = err.source {
+ info.errno = Some(source);
+
+ self.inner.lock().extended_error =
+ ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
}
}
@@ -1450,7 +1446,7 @@ fn reply_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
info.to_pid = orig.from.process.task.pid();
// We need to complete the transaction even if we cannot complete building the reply.
- let out = (|| -> BinderResult<_> {
+ if let Err(err) = (|| -> BinderResult<_> {
let completion = DTRWrap::arc_try_new(DeliverCode::new(
BR_TRANSACTION_COMPLETE,
self.process.task.pid(),
@@ -1471,11 +1467,10 @@ fn reply_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
}
orig.from.deliver_reply(Ok(reply), &orig, None);
Ok(())
- })()
- .map_err(|mut err| {
+ })() {
// At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let
// the sender know that the transaction has completed (with an error in this case).
-
+ self.push_return_work(BR_TRANSACTION_COMPLETE);
let param = err.source.as_ref().map_or(0, |e| e.to_errno());
let ee = ExtendedError::new(info.debug_id as u32, err.reply, param);
orig.from
@@ -1483,11 +1478,9 @@ fn reply_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
info.reply = BR_FAILED_REPLY;
info.errno = err.source;
info.error_line = Some(err.line);
- err.reply = BR_TRANSACTION_COMPLETE;
- err
- });
+ }
- out
+ Ok(())
}
fn oneway_transaction_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
---
base-commit: 65ba8f34ec886ec72b2c07ddc8cf3d815c32869d
change-id: 20261028-binder-reply-fail-72919fee2e91
Best regards,
--
Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-28 9:46 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-28 9:46 [PATCH] rust_binder: push BR_TRANSACTION_COMPLETE before BR_FAILED_REPLY Alice Ryhl
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®