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