summaryrefslogtreecommitdiffstats
path: root/drivers/android/binder/context.rs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-09-05 11:59:05 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-09-05 11:59:05 -0700
commit9f0346dcbea363787186c94ef94dd01aaa215afa (patch)
treeb81c168f4d0dbe4c7f4750f4598d48a6deb72094 /drivers/android/binder/context.rs
downloadlinux-stable-9f0346dcbea363787186c94ef94dd01aaa215afa.tar.gz
linux-stable-9f0346dcbea363787186c94ef94dd01aaa215afa.zip
Merge tag 'driver-core-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-coregrafted
Pull driver core fixes from Danilo Krummrich: - Fix kernfs listxattr() not returning security xattr names (e.g. SELinux labels) when the kernfs node has no allocated kernfs_iattrs - Fix silent truncation of IRQ vector indices in the Rust PCI abstractions - Don't select OF from DRIVER_PE_KUNIT_TEST; skip the test when OF is disabled instead of silently enabling extra kernel functionality - Russ Weight is retiring from kernel development; update the Firmware Loader sysfs contact to the driver-core mailing list, add a CREDITS entry for Firmware Upload, and update MAINTAINERS accordingly * tag 'driver-core-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: MAINTAINERS: Remove Russ Weight from Firmware Loader CREDITS: Add CREDITS entry for Firmware Upload firmware_loader: Change contact for sysfs nodes rust: pci: reject IRQ vector indices that do not fit in u32 kernfs: preserve security xattrs without allocating iattrs drivers: base: test: DRIVER_PE_KUNIT_TEST should not select OF
Diffstat (limited to 'drivers/android/binder/context.rs')
-rw-r--r--drivers/android/binder/context.rs175
1 files changed, 175 insertions, 0 deletions
diff --git a/drivers/android/binder/context.rs b/drivers/android/binder/context.rs
new file mode 100644
index 000000000..ddddb66b3
--- /dev/null
+++ b/drivers/android/binder/context.rs
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+use kernel::{
+ alloc::kvec::KVVec,
+ error::code::*,
+ prelude::*,
+ security,
+ str::{CStr, CString},
+ sync::{Arc, Mutex},
+ task::Kuid,
+};
+
+use crate::{error::BinderError, node::NodeRef, process::Process};
+
+kernel::sync::global_lock! {
+ // SAFETY: We call `init` in the module initializer, so it's initialized before first use.
+ pub(crate) unsafe(uninit) static CONTEXTS: Mutex<ContextList> = ContextList {
+ contexts: KVVec::new(),
+ };
+}
+
+pub(crate) struct ContextList {
+ contexts: KVVec<Arc<Context>>,
+}
+
+pub(crate) fn get_all_contexts() -> Result<KVVec<Arc<Context>>> {
+ let lock = CONTEXTS.lock();
+ let mut ctxs = KVVec::with_capacity(lock.contexts.len(), GFP_KERNEL)?;
+ for ctx in lock.contexts.iter() {
+ ctxs.push(ctx.clone(), GFP_KERNEL)?;
+ }
+ Ok(ctxs)
+}
+
+/// This struct keeps track of the processes using this context, and which process is the context
+/// manager.
+struct Manager {
+ node: Option<NodeRef>,
+ uid: Option<Kuid>,
+ all_procs: KVVec<Arc<Process>>,
+}
+
+/// There is one context per binder file (/dev/binder, /dev/hwbinder, etc)
+#[pin_data]
+pub(crate) struct Context {
+ #[pin]
+ manager: Mutex<Manager>,
+ pub(crate) name: CString,
+}
+
+impl Context {
+ pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
+ let name = CString::try_from(name)?;
+ let ctx = Arc::pin_init(
+ try_pin_init!(Context {
+ name,
+ manager <- kernel::new_mutex!(Manager {
+ all_procs: KVVec::new(),
+ node: None,
+ uid: None,
+ }, "Context::manager"),
+ }),
+ GFP_KERNEL,
+ )?;
+
+ CONTEXTS.lock().contexts.push(ctx.clone(), GFP_KERNEL)?;
+
+ Ok(ctx)
+ }
+
+ /// Called when the file for this context is unlinked.
+ ///
+ /// No-op if called twice.
+ pub(crate) fn deregister(self: &Arc<Self>) {
+ // Safe removal using retain
+ CONTEXTS.lock().contexts.retain(|c| !Arc::ptr_eq(c, self));
+ }
+
+ pub(crate) fn register_process(self: &Arc<Self>, proc: Arc<Process>) -> Result {
+ if !Arc::ptr_eq(self, &proc.ctx) {
+ pr_err!("Context::register_process called on the wrong context.");
+ return Err(EINVAL);
+ }
+ self.manager.lock().all_procs.push(proc, GFP_KERNEL)?;
+ Ok(())
+ }
+
+ pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Arc<Process>) {
+ if !Arc::ptr_eq(self, &proc.ctx) {
+ pr_err!("Context::deregister_process called on the wrong context.");
+ return;
+ }
+ let mut manager = self.manager.lock();
+ manager.all_procs.retain(|p| !Arc::ptr_eq(p, proc));
+
+ // Shrink the vector if it has significant unused capacity to avoid memory waste,
+ // but use a conservative strategy to prevent shrink-then-regrow oscillation.
+ // Only shrink when length drops below 1/4 of capacity, and shrink to twice the length.
+ let len = manager.all_procs.len();
+ let cap = manager.all_procs.capacity();
+ if len < cap / 4 {
+ // Shrink to twice the current length. Ignore allocation failures since this
+ // is just an optimization; the vector remains valid even if shrinking fails.
+ let _ = manager.all_procs.shrink_to(len * 2, GFP_KERNEL);
+ }
+ }
+
+ pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
+ let mut manager = self.manager.lock();
+ if manager.node.is_some() {
+ pr_warn!("BINDER_SET_CONTEXT_MGR already set");
+ return Err(EBUSY);
+ }
+ security::binder_set_context_mgr(&node_ref.node.owner.cred)?;
+
+ // If the context manager has been set before, ensure that we use the same euid.
+ let caller_uid = Kuid::current_euid();
+ if let Some(ref uid) = manager.uid {
+ if *uid != caller_uid {
+ return Err(EPERM);
+ }
+ }
+
+ manager.node = Some(node_ref);
+ manager.uid = Some(caller_uid);
+ Ok(())
+ }
+
+ pub(crate) fn unset_manager_node(&self) {
+ let node_ref = self.manager.lock().node.take();
+ drop(node_ref);
+ }
+
+ pub(crate) fn get_manager_node(&self, strong: bool) -> Result<NodeRef, BinderError> {
+ self.manager
+ .lock()
+ .node
+ .as_ref()
+ .ok_or_else(BinderError::new_dead)?
+ .clone(strong)
+ .map_err(BinderError::from)
+ }
+
+ pub(crate) fn for_each_proc<F>(&self, mut func: F)
+ where
+ F: FnMut(&Process),
+ {
+ let lock = self.manager.lock();
+ for proc in &lock.all_procs {
+ func(proc);
+ }
+ }
+
+ pub(crate) fn get_all_procs(&self) -> Result<KVVec<Arc<Process>>> {
+ let lock = self.manager.lock();
+ let mut procs = KVVec::with_capacity(lock.all_procs.len(), GFP_KERNEL)?;
+ for proc in lock.all_procs.iter() {
+ procs.push(Arc::clone(proc), GFP_KERNEL)?;
+ }
+ Ok(procs)
+ }
+
+ pub(crate) fn get_procs_with_pid(&self, pid: i32) -> Result<KVVec<Arc<Process>>> {
+ let lock = self.manager.lock();
+ let mut matching_procs = KVVec::new();
+ for proc in lock.all_procs.iter() {
+ if proc.task.pid() == pid {
+ matching_procs.push(Arc::clone(proc), GFP_KERNEL)?;
+ }
+ }
+ Ok(matching_procs)
+ }
+}