175 lines · 5.4 KB · Rust
RawDownload
// 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)    }}