| // 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) | |
| } | |
| } |