File Index
Files and directories
Sign in
FILE

context.rs

File preview with syntax highlighting.

linux-6.19.14/drivers/android/binder/context.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3// Copyright (C) 2025 Google LLC.
  4
  5use kernel::{
  6    error::Error,
  7    list::{List, ListArc, ListLinks},
  8    prelude::*,
  9    security,
 10    str::{CStr, CString},
 11    sync::{Arc, Mutex},
 12    task::Kuid,
 13};
 14
 15use crate::{error::BinderError, node::NodeRef, process::Process};
 16
 17kernel::sync::global_lock! {
 18    // SAFETY: We call `init` in the module initializer, so it's initialized before first use.
 19    pub(crate) unsafe(uninit) static CONTEXTS: Mutex<ContextList> = ContextList {
 20        list: List::new(),
 21    };
 22}
 23
 24pub(crate) struct ContextList {
 25    list: List<Context>,
 26}
 27
 28pub(crate) fn get_all_contexts() -> Result<KVec<Arc<Context>>> {
 29    let lock = CONTEXTS.lock();
 30
 31    let count = lock.list.iter().count();
 32
 33    let mut ctxs = KVec::with_capacity(count, GFP_KERNEL)?;
 34    for ctx in &lock.list {
 35        ctxs.push(Arc::from(ctx), GFP_KERNEL)?;
 36    }
 37    Ok(ctxs)
 38}
 39
 40/// This struct keeps track of the processes using this context, and which process is the context
 41/// manager.
 42struct Manager {
 43    node: Option<NodeRef>,
 44    uid: Option<Kuid>,
 45    all_procs: List<Process>,
 46}
 47
 48/// There is one context per binder file (/dev/binder, /dev/hwbinder, etc)
 49#[pin_data]
 50pub(crate) struct Context {
 51    #[pin]
 52    manager: Mutex<Manager>,
 53    pub(crate) name: CString,
 54    #[pin]
 55    links: ListLinks,
 56}
 57
 58kernel::list::impl_list_arc_safe! {
 59    impl ListArcSafe<0> for Context { untracked; }
 60}
 61kernel::list::impl_list_item! {
 62    impl ListItem<0> for Context {
 63        using ListLinks { self.links };
 64    }
 65}
 66
 67impl Context {
 68    pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
 69        let name = CString::try_from(name)?;
 70        let list_ctx = ListArc::pin_init::<Error>(
 71            try_pin_init!(Context {
 72                name,
 73                links <- ListLinks::new(),
 74                manager <- kernel::new_mutex!(Manager {
 75                    all_procs: List::new(),
 76                    node: None,
 77                    uid: None,
 78                }, "Context::manager"),
 79            }),
 80            GFP_KERNEL,
 81        )?;
 82
 83        let ctx = list_ctx.clone_arc();
 84        CONTEXTS.lock().list.push_back(list_ctx);
 85
 86        Ok(ctx)
 87    }
 88
 89    /// Called when the file for this context is unlinked.
 90    ///
 91    /// No-op if called twice.
 92    pub(crate) fn deregister(&self) {
 93        // SAFETY: We never add the context to any other linked list than this one, so it is either
 94        // in this list, or not in any list.
 95        unsafe { CONTEXTS.lock().list.remove(self) };
 96    }
 97
 98    pub(crate) fn register_process(self: &Arc<Self>, proc: ListArc<Process>) {
 99        if !Arc::ptr_eq(self, &proc.ctx) {
100            pr_err!("Context::register_process called on the wrong context.");
101            return;
102        }
103        self.manager.lock().all_procs.push_back(proc);
104    }
105
106    pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Process) {
107        if !Arc::ptr_eq(self, &proc.ctx) {
108            pr_err!("Context::deregister_process called on the wrong context.");
109            return;
110        }
111        // SAFETY: We just checked that this is the right list.
112        unsafe { self.manager.lock().all_procs.remove(proc) };
113    }
114
115    pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
116        let mut manager = self.manager.lock();
117        if manager.node.is_some() {
118            pr_warn!("BINDER_SET_CONTEXT_MGR already set");
119            return Err(EBUSY);
120        }
121        security::binder_set_context_mgr(&node_ref.node.owner.cred)?;
122
123        // If the context manager has been set before, ensure that we use the same euid.
124        let caller_uid = Kuid::current_euid();
125        if let Some(ref uid) = manager.uid {
126            if *uid != caller_uid {
127                return Err(EPERM);
128            }
129        }
130
131        manager.node = Some(node_ref);
132        manager.uid = Some(caller_uid);
133        Ok(())
134    }
135
136    pub(crate) fn unset_manager_node(&self) {
137        let node_ref = self.manager.lock().node.take();
138        drop(node_ref);
139    }
140
141    pub(crate) fn get_manager_node(&self, strong: bool) -> Result<NodeRef, BinderError> {
142        self.manager
143            .lock()
144            .node
145            .as_ref()
146            .ok_or_else(BinderError::new_dead)?
147            .clone(strong)
148            .map_err(BinderError::from)
149    }
150
151    pub(crate) fn for_each_proc<F>(&self, mut func: F)
152    where
153        F: FnMut(&Process),
154    {
155        let lock = self.manager.lock();
156        for proc in &lock.all_procs {
157            func(&proc);
158        }
159    }
160
161    pub(crate) fn get_all_procs(&self) -> Result<KVec<Arc<Process>>> {
162        let lock = self.manager.lock();
163        let count = lock.all_procs.iter().count();
164
165        let mut procs = KVec::with_capacity(count, GFP_KERNEL)?;
166        for proc in &lock.all_procs {
167            procs.push(Arc::from(proc), GFP_KERNEL)?;
168        }
169        Ok(procs)
170    }
171
172    pub(crate) fn get_procs_with_pid(&self, pid: i32) -> Result<KVec<Arc<Process>>> {
173        let orig = self.get_all_procs()?;
174        let mut backing = KVec::with_capacity(orig.len(), GFP_KERNEL)?;
175        for proc in orig.into_iter().filter(|proc| proc.task.pid() == pid) {
176            backing.push(proc, GFP_KERNEL)?;
177        }
178        Ok(backing)
179    }
180}
~/ Read-only file preview.