From 4c19719eb8b8df08c5bec7c499f73ddaea6f09fc Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 14 Apr 2026 12:02:34 +0000 Subject: rust_binder: avoid calling pending_oneway_finished() on TF_UPDATE_TXN When an outdated transaction is removed from `oneway_todo` due to `TF_UPDATE_TXN`, its `Allocation` is dropped. The current implementation of `Allocation::drop` calls `pending_oneway_finished()`, assuming the transaction was executed. This leads to premature execution of the next queued one-way transaction. Fix this by taking the `oneway_node` from the `Allocation` of the outdated transaction before it is dropped. This prevents `Allocation::drop` from signaling completion. We do not call `take_oneway_node()` from `Transaction::cancel` because it's actually correct to call `pending_oneway_finished()` on cancel if the transaction did not come from `oneway_todo`. This ensures that if `BINDER_THREAD_EXIT` is invoked and cancels a oneway transaction, then the next transaction is taken from `oneway_todo`. This bug does not lead to any issues in the kernel, but may lead to Binder delivering transactions to userspace earlier than userspace expected to receive them. Cc: stable Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") Assisted-by: Antigravity:gemini Signed-off-by: Alice Ryhl Acked-by: Carlos Llamas Link: https://patch.msgid.link/20260414-tf-update-txn-fix-v1-1-d2b83303acc9@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/allocation.rs | 8 ++++++++ drivers/android/binder/transaction.rs | 11 ++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/android') diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs index 0cab959e4b7e..b7b05e72970a 100644 --- a/drivers/android/binder/allocation.rs +++ b/drivers/android/binder/allocation.rs @@ -157,6 +157,14 @@ impl Allocation { self.get_or_init_info().target_node = Some(target_node); } + pub(crate) fn take_oneway_node(&mut self) -> Option> { + if let Some(info) = self.allocation_info.as_mut() { + info.oneway_node.take() + } else { + None + } + } + /// Reserve enough space to push at least `num_fds` fds. pub(crate) fn info_add_fd_reserve(&mut self, num_fds: usize) -> Result { self.get_or_init_info() diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs index 47d5e4d88b07..1d9b66920a21 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -270,7 +270,8 @@ impl Transaction { /// Not used for replies. pub(crate) fn submit(self: DLArc, info: &mut TransactionInfo) -> BinderResult { // Defined before `process_inner` so that the destructor runs after releasing the lock. - let mut _t_outdated; + let _t_outdated; + let _oneway_node; let oneway = self.flags & TF_ONE_WAY != 0; let process = self.to.clone(); @@ -287,6 +288,14 @@ impl Transaction { if let Some(t_outdated) = target_node.take_outdated_transaction(&self, &mut process_inner) { + let mut alloc_guard = t_outdated.allocation.lock(); + if let Some(alloc) = (*alloc_guard).as_mut() { + // Take the oneway node to prevent `Allocation::drop` from calling + // `pending_oneway_finished()`, which would be incorrect as this + // transaction is not being submitted. + _oneway_node = alloc.take_oneway_node(); + } + drop(alloc_guard); // Save the transaction to be dropped after locks are released. _t_outdated = t_outdated; } -- cgit v1.2.3 From f6d8fea9e3953151a4adb4f603503dc3dc9c69da Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Fri, 3 Apr 2026 18:18:58 +0000 Subject: rust_binder: Avoid holding lock when dropping delivered_death In 6c37bebd8c926, we switched to looping over the list and dropping each individual node, ostensibly without the lock held in the loop body. If the kernel were using Rust Edition 2024, the comment would be accurate, and the lock would not be held across the drop. However, the kernel is currently using 2021, so tail expression lifetime extension results in the lock being held across the drop. Explicitly binding the expression result to a variable makes the lockguard no longer part of a tail expression, causing the lock to be dropped before entering the loop body. This was detected via `CONFIG_PROVE_LOCKING` identifying an invalid wait context at the drop site. Reported-by: David Stevens Signed-off-by: Matthew Maurer Cc: stable Fixes: 6c37bebd8c92 ("rust_binder: avoid mem::take on delivered_deaths") Reviewed-by: Alice Ryhl Acked-by: Carlos Llamas Link: https://patch.msgid.link/20260403-lockhold-v1-1-c332b56cd8ae@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder/process.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/android') diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index 820cbd541435..96b8440ceac6 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -1402,7 +1402,12 @@ impl Process { // Clear delivered_deaths list. // // Scope ensures that MutexGuard is dropped while executing the body. - while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } { + while let Some(delivered_death) = { + // Explicitly bind to avoid tail expression lifetime extension of the lockguard + // Can be removed when the kernel moves to edition 2024 + let maybe_death = self.inner.lock().delivered_deaths.pop_front(); + maybe_death + } { drop(delivered_death); } -- cgit v1.2.3