summaryrefslogtreecommitdiffstats
path: root/drivers/android/binder/node.rs
diff options
context:
space:
mode:
authorAlice Ryhl <aliceryhl@google.com>2026-09-03 11:36:03 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-16 19:33:40 +0100
commit2a74ccd1bcc170e66525f34e9de8652b57e2cf3d (patch)
tree1c2fcae7c8864a2bbeb61822238038a1acfecc5d /drivers/android/binder/node.rs
parent62479b6e5df82cbdf3c4145130928f233fae78fb (diff)
downloadlinux-stable-2a74ccd1bcc170e66525f34e9de8652b57e2cf3d.tar.gz
linux-stable-2a74ccd1bcc170e66525f34e9de8652b57e2cf3d.zip
rust_binder: reschedule node refcount update on thread exit
When a thread exits via BINDER_THREAD_EXIT, its pending work items are cancelled. If a thread exits while holding a pending node refcount increment (e.g. pushed as deferred work to that thread), the refcount increment was previously dropped because Node::cancel() and NodeWrapper::cancel() were no-ops. Dropping the refcount update leaves the node's delivery state and count state desynchronized, and userspace will not receive the notification, which can cause the node to never be freed from the process's nodes tree when all external references are dropped. Fix this by implementing DeliverToRead::cancel() for Node and NodeWrapper to move the pending refcount update to the process's work queue on thread exit so another thread can deliver it to userspace. Cc: stable <stable@kernel.org> Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://patch.msgid.link/20260903-binder-thread-exit-node-v1-1-be09ff14f6a4@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/android/binder/node.rs')
-rw-r--r--drivers/android/binder/node.rs20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs
index 0a82af14c..8dc3e3f2b 100644
--- a/drivers/android/binder/node.rs
+++ b/drivers/android/binder/node.rs
@@ -51,9 +51,9 @@ pub(crate) struct CouldNotDeliverCriticalIncrement;
/// about to drop the weak reference, then the strong increment could be processed after the
/// other thread has already exited, which would be too late.
///
-/// Note that trying to create a `ListArc` to the node can succeed even if `has_normal_push` is
+/// Note that trying to create a `ListArc` to the node can succeed even if `has_pushed_node` is
/// set. This is because another thread might just have popped the node from a todo list, but not
-/// yet called `do_work`. However, if `has_normal_push` is false, then creating a `ListArc` should
+/// yet called `do_work`. However, if `has_pushed_node` is false, then creating a `ListArc` should
/// always succeed.
///
/// Like the other fields in `NodeInner`, the delivery state is protected by the process lock.
@@ -738,7 +738,21 @@ impl DeliverToRead for Node {
self.do_work_locked(writer, owner_inner)
}
- fn cancel(self: DArc<Self>) {}
+ fn cancel(self: DArc<Self>) {
+ let _drop_outside_lock;
+ let mut owner_inner = self.owner.inner.lock();
+
+ // We only do something on BINDER_THREAD_EXIT, not process exit.
+ if owner_inner.is_dead {
+ return;
+ }
+
+ // If BINDER_THREAD_EXIT is invoked on a thread with a pending node refcount update, we
+ // should move ourselves to ensure the refcount update is still delivered.
+ if let Some(node) = ListArc::try_from_arc_borrow(self.as_arc_borrow()) {
+ _drop_outside_lock = owner_inner.push_work(&self.owner, node);
+ }
+ }
fn should_sync_wakeup(&self) -> bool {
false