[PATCH] rust_binder: enforce delivered death process ownership

From: Daniil Detkov via B4 Relay

Date: Wed Aug 05 2026 - 09:37:40 EST


From: Daniil Detkov <d4n11l@xxxxxxxxx>

The delivered_links field of NodeDeath may only be linked into the
delivered_deaths list owned by NodeDeath::process. The existing safe
ProcessInner::death_delivered method does not enforce that relationship,
so safe Rust can violate the invariant relied on by a later unsafe list
removal.

Move the insertion boundary to Process and validate both the supplied
guard and the NodeDeath owner before mutating the list. Keep the existing
lock order and duplicate-insertion behavior unchanged.

Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver")
Closes: https://github.com/Rust-for-Linux/linux/issues/1238
Assisted-by: Codex:5.6-Sol
Signed-off-by: Daniil Detkov <d4n11l@xxxxxxxxx>
---
drivers/android/binder/node.rs | 6 +++++-
drivers/android/binder/process.rs | 23 +++++++++++++++--------
2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs
index c10148e90..813718486 100644
--- a/drivers/android/binder/node.rs
+++ b/drivers/android/binder/node.rs
@@ -978,6 +978,10 @@ pub(crate) fn new(
))
}

+ pub(crate) fn belongs_to_process(&self, process: &Process) -> bool {
+ core::ptr::eq(&*self.process, process)
+ }
+
/// Sets the cleared flag to `true`.
///
/// It removes `self` from the node's death notification list if needed.
@@ -1103,7 +1107,7 @@ fn do_work(
}
// We're still holding the inner lock, so it cannot be aborted while we insert it into
// the delivered list.
- process_inner.death_delivered(self.clone());
+ process.death_delivered(&mut process_inner, self.clone());
BR_DEAD_BINDER
};

diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs
index cdd1a9079..5c5ce7c01 100644
--- a/drivers/android/binder/process.rs
+++ b/drivers/android/binder/process.rs
@@ -309,14 +309,6 @@ fn pull_delivered_death(&mut self, cookie: u64) -> Option<DArc<NodeDeath>> {
None
}

- pub(crate) fn death_delivered(&mut self, death: DArc<NodeDeath>) {
- if let Some(death) = ListArc::try_from_arc_or_drop(death) {
- self.delivered_deaths.push_back(death);
- } else {
- pr_warn!("Notification added to `delivered_deaths` twice.");
- }
- }
-
pub(crate) fn add_outstanding_txn(&mut self) {
self.outstanding_txns += 1;
}
@@ -920,6 +912,21 @@ pub(crate) fn get_node_from_handle(&self, handle: u32, strong: bool) -> Result<N
.clone(strong)
}

+ pub(crate) fn death_delivered(
+ &self,
+ inner: &mut Guard<'_, ProcessInner, SpinLockBackend>,
+ death: DArc<NodeDeath>,
+ ) {
+ assert!(core::ptr::eq(&self.inner, inner.lock_ref()));
+ assert!(death.belongs_to_process(self));
+
+ if let Some(death) = ListArc::try_from_arc_or_drop(death) {
+ inner.delivered_deaths.push_back(death);
+ } else {
+ pr_warn!("Notification added to `delivered_deaths` twice.");
+ }
+ }
+
pub(crate) fn remove_from_delivered_deaths(&self, death: &DArc<NodeDeath>) {
let mut inner = self.inner.lock();
// SAFETY: By the invariant on the `delivered_links` field, this is the right linked list.

---
base-commit: 075b74841bd0065a3bda3440873c747938e69b68
change-id: 20260805-fix-rust-binder-death-ownership-affac3fef3ab

Best regards,
--
Daniil Detkov <d4n11l@xxxxxxxxx>