• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2024 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 
get_all_contexts() -> Result<KVec<Arc<Context>>>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_has_list_links! {
59     impl HasListLinks<0> for Context { self.links }
60 }
61 kernel::list::impl_list_arc_safe! {
62     impl ListArcSafe<0> for Context { untracked; }
63 }
64 kernel::list::impl_list_item! {
65     impl ListItem<0> for Context {
66         using ListLinks;
67     }
68 }
69 
70 impl Context {
new(name: &CStr) -> Result<Arc<Self>>71     pub(crate) fn new(name: &CStr) -> Result<Arc<Self>> {
72         let name = CString::try_from(name)?;
73         let list_ctx = ListArc::pin_init::<Error>(
74             try_pin_init!(Context {
75                 name,
76                 links <- ListLinks::new(),
77                 manager <- kernel::new_mutex!(Manager {
78                     all_procs: List::new(),
79                     node: None,
80                     uid: None,
81                 }, "Context::manager"),
82             }),
83             GFP_KERNEL,
84         )?;
85 
86         let ctx = list_ctx.clone_arc();
87         CONTEXTS.lock().list.push_back(list_ctx);
88 
89         Ok(ctx)
90     }
91 
92     /// Called when the file for this context is unlinked.
93     ///
94     /// No-op if called twice.
deregister(&self)95     pub(crate) fn deregister(&self) {
96         // SAFETY: We never add the context to any other linked list than this one, so it is either
97         // in this list, or not in any list.
98         unsafe { CONTEXTS.lock().list.remove(self) };
99     }
100 
register_process(self: &Arc<Self>, proc: ListArc<Process>)101     pub(crate) fn register_process(self: &Arc<Self>, proc: ListArc<Process>) {
102         if !Arc::ptr_eq(self, &proc.ctx) {
103             pr_err!("Context::register_process called on the wrong context.");
104             return;
105         }
106         self.manager.lock().all_procs.push_back(proc);
107     }
108 
deregister_process(self: &Arc<Self>, proc: &Process)109     pub(crate) fn deregister_process(self: &Arc<Self>, proc: &Process) {
110         if !Arc::ptr_eq(self, &proc.ctx) {
111             pr_err!("Context::deregister_process called on the wrong context.");
112             return;
113         }
114         // SAFETY: We just checked that this is the right list.
115         unsafe { self.manager.lock().all_procs.remove(proc) };
116     }
117 
set_manager_node(&self, node_ref: NodeRef) -> Result118     pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result {
119         let mut manager = self.manager.lock();
120         if manager.node.is_some() {
121             pr_warn!("BINDER_SET_CONTEXT_MGR already set");
122             return Err(EBUSY);
123         }
124         security::binder_set_context_mgr(&node_ref.node.owner.cred)?;
125 
126         // If the context manager has been set before, ensure that we use the same euid.
127         let caller_uid = Kuid::current_euid();
128         if let Some(ref uid) = manager.uid {
129             if *uid != caller_uid {
130                 return Err(EPERM);
131             }
132         }
133 
134         manager.node = Some(node_ref);
135         manager.uid = Some(caller_uid);
136         Ok(())
137     }
138 
unset_manager_node(&self)139     pub(crate) fn unset_manager_node(&self) {
140         let node_ref = self.manager.lock().node.take();
141         drop(node_ref);
142     }
143 
get_manager_node(&self, strong: bool) -> Result<NodeRef, BinderError>144     pub(crate) fn get_manager_node(&self, strong: bool) -> Result<NodeRef, BinderError> {
145         self.manager
146             .lock()
147             .node
148             .as_ref()
149             .ok_or_else(BinderError::new_dead)?
150             .clone(strong)
151             .map_err(BinderError::from)
152     }
153 
for_each_proc<F>(&self, mut func: F) where F: FnMut(&Process),154     pub(crate) fn for_each_proc<F>(&self, mut func: F)
155     where
156         F: FnMut(&Process),
157     {
158         let lock = self.manager.lock();
159         for proc in &lock.all_procs {
160             func(&proc);
161         }
162     }
163 
get_all_procs(&self) -> Result<KVec<Arc<Process>>>164     pub(crate) fn get_all_procs(&self) -> Result<KVec<Arc<Process>>> {
165         let lock = self.manager.lock();
166         let count = lock.all_procs.iter().count();
167 
168         let mut procs = KVec::with_capacity(count, GFP_KERNEL)?;
169         for proc in &lock.all_procs {
170             procs.push(Arc::from(proc), GFP_KERNEL)?;
171         }
172         Ok(procs)
173     }
174 
get_procs_with_pid(&self, pid: i32) -> Result<KVec<Arc<Process>>>175     pub(crate) fn get_procs_with_pid(&self, pid: i32) -> Result<KVec<Arc<Process>>> {
176         let orig = self.get_all_procs()?;
177         let mut backing = KVec::with_capacity(orig.len(), GFP_KERNEL)?;
178         for proc in orig.into_iter().filter(|proc| proc.task.pid() == pid) {
179             backing.push(proc, GFP_KERNEL)?;
180         }
181         Ok(backing)
182     }
183 }
184