xref: /linux/drivers/android/binder/context.rs (revision eafedbc7c050c44744fbdf80bdf3315e860b7513)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2025 Google LLC.
4 
5 use 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 
15 use crate::{error::BinderError, node::NodeRef, process::Process};
16 
17 kernel::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 
24 pub(crate) struct ContextList {
25     list: List<Context>,
26 }
27 
28 pub(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.
42 struct 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]
50 pub(crate) struct Context {
51     #[pin]
52     manager: Mutex<Manager>,
53     pub(crate) name: CString,
54     #[pin]
55     links: ListLinks,
56 }
57 
58 kernel::list::impl_list_arc_safe! {
59     impl ListArcSafe<0> for Context { untracked; }
60 }
61 kernel::list::impl_list_item! {
62     impl ListItem<0> for Context {
63         using ListLinks { self.links };
64     }
65 }
66 
67 impl 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 }
181