xref: /linux/drivers/android/binder/freeze.rs (revision fbf64f3595a68b56df324bdea96fb03542ae9334)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2025 Google LLC.
4 
5 use kernel::{
6     alloc::AllocError,
7     list::ListArc,
8     prelude::*,
9     rbtree::{self, RBTreeNodeReservation},
10     seq_file::SeqFile,
11     seq_print,
12     sync::{Arc, UniqueArc},
13     uaccess::UserSliceReader,
14 };
15 
16 use crate::{
17     defs::*, node::Node, process::Process, thread::Thread, BinderReturnWriter, DArc, DLArc,
18     DTRWrap, DeliverToRead,
19 };
20 
21 #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
22 pub(crate) struct FreezeCookie(u64);
23 
24 /// Represents a listener for changes to the frozen state of a process.
25 pub(crate) struct FreezeListener {
26     /// The node we are listening for.
27     pub(crate) node: DArc<Node>,
28     /// The cookie of this freeze listener.
29     cookie: FreezeCookie,
30     /// What value of `is_frozen` did we most recently tell userspace about?
31     last_is_frozen: Option<bool>,
32     /// We sent a `BR_FROZEN_BINDER` and we are waiting for `BC_FREEZE_NOTIFICATION_DONE` before
33     /// sending any other commands.
34     is_pending: bool,
35     /// Userspace sent `BC_CLEAR_FREEZE_NOTIFICATION` and we need to reply with
36     /// `BR_CLEAR_FREEZE_NOTIFICATION_DONE` as soon as possible. If `is_pending` is set, then we
37     /// must wait for it to be unset before we can reply.
38     is_clearing: bool,
39     /// Number of cleared duplicates that can't be deleted until userspace sends
40     /// `BC_FREEZE_NOTIFICATION_DONE`.
41     num_pending_duplicates: u64,
42     /// Number of cleared duplicates that can be deleted.
43     num_cleared_duplicates: u64,
44 }
45 
46 impl FreezeListener {
47     /// Is it okay to create a new listener with the same cookie as this one for the provided node?
48     ///
49     /// Under some scenarios, userspace may delete a freeze listener and immediately recreate it
50     /// with the same cookie. This results in duplicate listeners. To avoid issues with ambiguity,
51     /// we allow this only if the new listener is for the same node, and we also require that the
52     /// old listener has already been cleared.
53     fn allow_duplicate(&self, node: &DArc<Node>) -> bool {
54         Arc::ptr_eq(&self.node, node) && self.is_clearing
55     }
56 }
57 
58 type UninitFM = UniqueArc<core::mem::MaybeUninit<DTRWrap<FreezeMessage>>>;
59 
60 /// Represents a notification that the freeze state has changed.
61 pub(crate) struct FreezeMessage {
62     cookie: FreezeCookie,
63 }
64 
65 kernel::list::impl_list_arc_safe! {
66     impl ListArcSafe<0> for FreezeMessage {
67         untracked;
68     }
69 }
70 
71 impl FreezeMessage {
72     fn new(flags: kernel::alloc::Flags) -> Result<UninitFM, AllocError> {
73         UniqueArc::new_uninit(flags)
74     }
75 
76     fn init(ua: UninitFM, cookie: FreezeCookie) -> DLArc<FreezeMessage> {
77         match ua.pin_init_with(DTRWrap::new(FreezeMessage { cookie })) {
78             Ok(msg) => ListArc::from(msg),
79             Err(err) => match err {},
80         }
81     }
82 }
83 
84 impl DeliverToRead for FreezeMessage {
85     fn do_work(
86         self: DArc<Self>,
87         thread: &Thread,
88         writer: &mut BinderReturnWriter<'_>,
89     ) -> Result<bool> {
90         let _removed_listener;
91         let mut node_refs = thread.process.node_refs.lock();
92         let Some(mut freeze_entry) = node_refs.freeze_listeners.find_mut(&self.cookie) else {
93             return Ok(true);
94         };
95         let freeze = freeze_entry.get_mut();
96 
97         if freeze.num_cleared_duplicates > 0 {
98             freeze.num_cleared_duplicates -= 1;
99             drop(node_refs);
100             writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;
101             writer.write_payload(&self.cookie.0)?;
102             return Ok(true);
103         }
104 
105         if freeze.is_pending {
106             return Ok(true);
107         }
108         if freeze.is_clearing {
109             kernel::warn_on!(freeze.num_cleared_duplicates != 0);
110             if freeze.num_pending_duplicates > 0 {
111                 // The primary freeze listener was deleted, so convert a pending duplicate back
112                 // into the primary one.
113                 freeze.num_pending_duplicates -= 1;
114                 freeze.is_pending = true;
115                 freeze.is_clearing = true;
116             } else {
117                 _removed_listener = freeze_entry.remove_node();
118             }
119             drop(node_refs);
120             writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;
121             writer.write_payload(&self.cookie.0)?;
122             Ok(true)
123         } else {
124             let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
125             if freeze.last_is_frozen == Some(is_frozen) {
126                 return Ok(true);
127             }
128 
129             let mut state_info = BinderFrozenStateInfo::default();
130             state_info.is_frozen = u32::from(is_frozen);
131             state_info.cookie = freeze.cookie.0;
132             freeze.is_pending = true;
133             freeze.last_is_frozen = Some(is_frozen);
134             drop(node_refs);
135 
136             writer.write_code(BR_FROZEN_BINDER)?;
137             writer.write_payload(&state_info)?;
138             // BR_FROZEN_BINDER notifications can cause transactions
139             Ok(false)
140         }
141     }
142 
143     fn cancel(self: DArc<Self>) {}
144 
145     fn should_sync_wakeup(&self) -> bool {
146         false
147     }
148 
149     #[inline(never)]
150     fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
151         seq_print!(m, "{}has frozen binder\n", prefix);
152         Ok(())
153     }
154 }
155 
156 impl FreezeListener {
157     /// Called when this freeze listener is cleared abnormally.
158     ///
159     /// This occurs either because the process exited or because the process dropped its last
160     /// refcount on the node ref without explicitly removing the freeze listener first.
161     ///
162     /// The returned `KVVec` is just a value that should be dropped outside of the lock.
163     pub(crate) fn on_process_cleanup(&self, proc: &Process) -> KVVec<Arc<Process>> {
164         if !self.is_clearing {
165             return self.node.remove_freeze_listener(proc);
166         }
167         KVVec::new()
168     }
169 }
170 
171 impl Process {
172     pub(crate) fn request_freeze_notif(
173         self: &Arc<Self>,
174         reader: &mut UserSliceReader,
175     ) -> Result<()> {
176         let hc = reader.read::<BinderHandleCookie>()?;
177         let handle = hc.handle;
178         let cookie = FreezeCookie(hc.cookie);
179 
180         let msg = FreezeMessage::new(GFP_KERNEL)?;
181         let alloc = RBTreeNodeReservation::new(GFP_KERNEL)?;
182 
183         let mut afl_vec_alloc = KVVec::new();
184         let mut info;
185         let mut freeze_entry;
186         let mut node_refs_guard = self.node_refs.lock();
187         loop {
188             let node_refs = &mut *node_refs_guard;
189             info = match node_refs.by_handle.get_mut(&handle) {
190                 Some(info) => info,
191                 None => {
192                     pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION invalid ref {}\n", handle);
193                     return Err(EINVAL);
194                 }
195             };
196             if info.freeze().is_some() {
197                 pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION already set\n");
198                 return Err(EINVAL);
199             }
200             let node_ref = info.node_ref();
201             freeze_entry = node_refs.freeze_listeners.entry(cookie);
202 
203             if let rbtree::Entry::Occupied(ref dupe) = freeze_entry {
204                 if !dupe.get().allow_duplicate(&node_ref.node) {
205                     pr_warn!("BC_REQUEST_FREEZE_NOTIFICATION duplicate cookie\n");
206                     return Err(EINVAL);
207                 }
208             }
209 
210             // Now we add to the node's freeze listener list, with retry and re-allocate if the
211             // vector is full.
212             //
213             // To ensure that the node is added atomically, this is the first time we modify any
214             // state. When this call succeeds, all other modifications must occur without the
215             // possibility for any failure paths.
216             match node_ref
217                 .node
218                 .add_freeze_listener(self, &mut afl_vec_alloc)?
219             {
220                 Ok(()) => break,
221                 Err(resize_target) => {
222                     drop(node_refs_guard);
223                     afl_vec_alloc = KVVec::with_capacity(resize_target, GFP_KERNEL)?;
224                     node_refs_guard = self.node_refs.lock();
225                 }
226             }
227         }
228 
229         match freeze_entry {
230             rbtree::Entry::Vacant(entry) => {
231                 entry.insert(
232                     FreezeListener {
233                         cookie,
234                         node: info.node_ref().node.clone(),
235                         last_is_frozen: None,
236                         is_pending: false,
237                         is_clearing: false,
238                         num_pending_duplicates: 0,
239                         num_cleared_duplicates: 0,
240                     },
241                     alloc,
242                 );
243             }
244             rbtree::Entry::Occupied(mut dupe) => {
245                 let dupe = dupe.get_mut();
246                 if dupe.is_pending {
247                     dupe.num_pending_duplicates += 1;
248                 } else {
249                     dupe.num_cleared_duplicates += 1;
250                 }
251                 dupe.last_is_frozen = None;
252                 dupe.is_pending = false;
253                 dupe.is_clearing = false;
254             }
255         }
256 
257         *info.freeze() = Some(cookie);
258         let msg = FreezeMessage::init(msg, cookie);
259         drop(node_refs_guard);
260         let _ = self.push_work(msg);
261         Ok(())
262     }
263 
264     pub(crate) fn freeze_notif_done(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> {
265         let cookie = FreezeCookie(reader.read()?);
266         let alloc = FreezeMessage::new(GFP_KERNEL)?;
267         let mut node_refs_guard = self.node_refs.lock();
268         let node_refs = &mut *node_refs_guard;
269         let Some(freeze) = node_refs.freeze_listeners.get_mut(&cookie) else {
270             pr_warn!("BC_FREEZE_NOTIFICATION_DONE {:016x} not found\n", cookie.0);
271             return Err(EINVAL);
272         };
273         let mut clear_msg = None;
274         if freeze.num_pending_duplicates > 0 {
275             clear_msg = Some(FreezeMessage::init(alloc, cookie));
276             freeze.num_pending_duplicates -= 1;
277             freeze.num_cleared_duplicates += 1;
278         } else {
279             if !freeze.is_pending {
280                 pr_warn!(
281                     "BC_FREEZE_NOTIFICATION_DONE {:016x} not pending\n",
282                     cookie.0
283                 );
284                 return Err(EINVAL);
285             }
286             let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
287             if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) {
288                 // Immediately send another FreezeMessage.
289                 clear_msg = Some(FreezeMessage::init(alloc, cookie));
290             }
291             freeze.is_pending = false;
292         }
293         drop(node_refs_guard);
294         if let Some(clear_msg) = clear_msg {
295             let _ = self.push_work(clear_msg);
296         }
297         Ok(())
298     }
299 
300     pub(crate) fn clear_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> {
301         let hc = reader.read::<BinderHandleCookie>()?;
302         let handle = hc.handle;
303         let cookie = FreezeCookie(hc.cookie);
304 
305         let _to_free_fl;
306         let alloc = FreezeMessage::new(GFP_KERNEL)?;
307         let mut node_refs_guard = self.node_refs.lock();
308         let node_refs = &mut *node_refs_guard;
309         let Some(info) = node_refs.by_handle.get_mut(&handle) else {
310             pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION invalid ref {}\n", handle);
311             return Err(EINVAL);
312         };
313         let Some(info_cookie) = info.freeze() else {
314             pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION freeze notification not active\n");
315             return Err(EINVAL);
316         };
317         if *info_cookie != cookie {
318             pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION freeze notification cookie mismatch\n");
319             return Err(EINVAL);
320         }
321         let Some(listener) = node_refs.freeze_listeners.get_mut(&cookie) else {
322             pr_warn!("BC_CLEAR_FREEZE_NOTIFICATION invalid cookie {}\n", handle);
323             return Err(EINVAL);
324         };
325         listener.is_clearing = true;
326         _to_free_fl = listener.node.remove_freeze_listener(self);
327         *info.freeze() = None;
328         let mut msg = None;
329         if !listener.is_pending {
330             msg = Some(FreezeMessage::init(alloc, cookie));
331         }
332         drop(node_refs_guard);
333 
334         if let Some(msg) = msg {
335             let _ = self.push_work(msg);
336         }
337         Ok(())
338     }
339 
340     fn get_freeze_cookie(&self, node: &DArc<Node>) -> Option<FreezeCookie> {
341         let node_refs = &mut *self.node_refs.lock();
342         let handle = node_refs.by_node.get(&node.global_id())?;
343         let node_ref = node_refs.by_handle.get_mut(handle)?;
344         *node_ref.freeze()
345     }
346 
347     /// Creates a vector of every freeze listener on this process.
348     ///
349     /// Returns pairs of the remote process listening for notifications and the local node it is
350     /// listening on.
351     #[expect(clippy::type_complexity)]
352     fn find_freeze_recipients(&self) -> Result<KVVec<(DArc<Node>, Arc<Process>)>, AllocError> {
353         // Defined before `inner` to drop after releasing spinlock if `push_within_capacity` fails.
354         let mut node_proc_pair;
355 
356         // We pre-allocate space for up to 8 recipients before we take the spinlock. However, if
357         // the allocation fails, use a vector with a capacity of zero instead of failing. After
358         // all, there might not be any freeze listeners, in which case this operation could still
359         // succeed.
360         let mut recipients =
361             KVVec::with_capacity(8, GFP_KERNEL).unwrap_or_else(|_err| KVVec::new());
362 
363         let mut inner = self.lock_with_nodes();
364         let mut curr = inner.nodes.cursor_front_mut();
365         while let Some(cursor) = curr {
366             let (key, node) = cursor.current();
367             let key = *key;
368             let list = node.freeze_list(&inner.inner);
369             let len = list.len();
370 
371             if recipients.spare_capacity_mut().len() < len {
372                 drop(inner);
373                 recipients.reserve(len, GFP_KERNEL)?;
374                 inner = self.lock_with_nodes();
375                 // Find the node we were looking at and try again. If the set of nodes was changed,
376                 // then just proceed to the next node. This is ok because we don't guarantee the
377                 // inclusion of nodes that are added or removed in parallel with this operation.
378                 curr = inner.nodes.cursor_lower_bound_mut(&key);
379                 continue;
380             }
381 
382             for proc in list {
383                 node_proc_pair = (node.clone(), proc.clone());
384                 recipients
385                     .push_within_capacity(node_proc_pair)
386                     .map_err(|_| {
387                         pr_err!(
388                             "push_within_capacity failed even though we checked the capacity\n"
389                         );
390                         AllocError
391                     })?;
392             }
393 
394             curr = cursor.move_next();
395         }
396         Ok(recipients)
397     }
398 
399     /// Prepare allocations for sending freeze messages.
400     pub(crate) fn prepare_freeze_messages(&self) -> Result<FreezeMessages, AllocError> {
401         let recipients = self.find_freeze_recipients()?;
402         let mut batch = KVVec::with_capacity(recipients.len(), GFP_KERNEL)?;
403         for (node, proc) in recipients {
404             let Some(cookie) = proc.get_freeze_cookie(&node) else {
405                 // If the freeze listener was removed in the meantime, just discard the
406                 // notification.
407                 continue;
408             };
409             let msg_alloc = FreezeMessage::new(GFP_KERNEL)?;
410             let msg = FreezeMessage::init(msg_alloc, cookie);
411             batch.push((proc, msg), GFP_KERNEL)?;
412         }
413 
414         Ok(FreezeMessages { batch })
415     }
416 }
417 
418 pub(crate) struct FreezeMessages {
419     batch: KVVec<(Arc<Process>, DLArc<FreezeMessage>)>,
420 }
421 
422 impl FreezeMessages {
423     pub(crate) fn send_messages(self) {
424         for (proc, msg) in self.batch {
425             let _ = proc.push_work(msg);
426         }
427     }
428 }
429