1 // SPDX-License-Identifier: GPL-2.0 2 3 // Copyright (C) 2025 Google LLC. 4 5 use core::mem::{size_of, size_of_val, MaybeUninit}; 6 use core::ops::Range; 7 8 use kernel::{ 9 bindings, 10 fs::file::{File, FileDescriptorReservation}, 11 prelude::*, 12 sync::{aref::ARef, Arc}, 13 transmute::{AsBytes, FromBytes}, 14 uaccess::UserSliceReader, 15 uapi, 16 }; 17 18 use crate::{ 19 deferred_close::DeferredFdCloser, 20 defs::*, 21 node::{Node, NodeRef}, 22 process::Process, 23 DArc, 24 }; 25 26 #[derive(Default)] 27 pub(crate) struct AllocationInfo { 28 /// Range within the allocation where we can find the offsets to the object descriptors. 29 pub(crate) offsets: Option<Range<usize>>, 30 /// The target node of the transaction this allocation is associated to. 31 /// Not set for replies. 32 pub(crate) target_node: Option<NodeRef>, 33 /// When this allocation is dropped, call `pending_oneway_finished` on the node. 34 /// 35 /// This is used to serialize oneway transaction on the same node. Binder guarantees that 36 /// oneway transactions to the same node are delivered sequentially in the order they are sent. 37 pub(crate) oneway_node: Option<DArc<Node>>, 38 /// Zero the data in the buffer on free. 39 pub(crate) clear_on_free: bool, 40 /// List of files embedded in this transaction. 41 file_list: FileList, 42 } 43 44 /// Represents an allocation that the kernel is currently using. 45 /// 46 /// When allocations are idle, the range allocator holds the data related to them. 47 /// 48 /// # Invariants 49 /// 50 /// This allocation corresponds to an allocation in the range allocator, so the relevant pages are 51 /// marked in use in the page range. 52 pub(crate) struct Allocation { 53 pub(crate) offset: usize, 54 size: usize, 55 pub(crate) ptr: usize, 56 pub(crate) process: Arc<Process>, 57 allocation_info: Option<AllocationInfo>, 58 free_on_drop: bool, 59 pub(crate) oneway_spam_detected: bool, 60 #[allow(dead_code)] 61 pub(crate) debug_id: usize, 62 } 63 64 impl Allocation { 65 pub(crate) fn new( 66 process: Arc<Process>, 67 debug_id: usize, 68 offset: usize, 69 size: usize, 70 ptr: usize, 71 oneway_spam_detected: bool, 72 ) -> Self { 73 Self { 74 process, 75 offset, 76 size, 77 ptr, 78 debug_id, 79 oneway_spam_detected, 80 allocation_info: None, 81 free_on_drop: true, 82 } 83 } 84 85 fn size_check(&self, offset: usize, size: usize) -> Result { 86 let overflow_fail = offset.checked_add(size).is_none(); 87 let cmp_size_fail = offset.wrapping_add(size) > self.size; 88 if overflow_fail || cmp_size_fail { 89 return Err(EFAULT); 90 } 91 Ok(()) 92 } 93 94 pub(crate) fn copy_into( 95 &self, 96 reader: &mut UserSliceReader, 97 offset: usize, 98 size: usize, 99 ) -> Result { 100 self.size_check(offset, size)?; 101 102 // SAFETY: While this object exists, the range allocator will keep the range allocated, and 103 // in turn, the pages will be marked as in use. 104 unsafe { 105 self.process 106 .pages 107 .copy_from_user_slice(reader, self.offset + offset, size) 108 } 109 } 110 111 pub(crate) fn read<T: FromBytes>(&self, offset: usize) -> Result<T> { 112 self.size_check(offset, size_of::<T>())?; 113 114 // SAFETY: While this object exists, the range allocator will keep the range allocated, and 115 // in turn, the pages will be marked as in use. 116 unsafe { self.process.pages.read(self.offset + offset) } 117 } 118 119 pub(crate) fn write<T: ?Sized>(&self, offset: usize, obj: &T) -> Result { 120 self.size_check(offset, size_of_val::<T>(obj))?; 121 122 // SAFETY: While this object exists, the range allocator will keep the range allocated, and 123 // in turn, the pages will be marked as in use. 124 unsafe { self.process.pages.write(self.offset + offset, obj) } 125 } 126 127 pub(crate) fn fill_zero(&self) -> Result { 128 // SAFETY: While this object exists, the range allocator will keep the range allocated, and 129 // in turn, the pages will be marked as in use. 130 unsafe { self.process.pages.fill_zero(self.offset, self.size) } 131 } 132 133 pub(crate) fn keep_alive(mut self) { 134 self.process 135 .buffer_make_freeable(self.offset, self.allocation_info.take()); 136 self.free_on_drop = false; 137 } 138 139 pub(crate) fn set_info(&mut self, info: AllocationInfo) { 140 self.allocation_info = Some(info); 141 } 142 143 pub(crate) fn get_or_init_info(&mut self) -> &mut AllocationInfo { 144 self.allocation_info.get_or_insert_with(Default::default) 145 } 146 147 pub(crate) fn set_info_offsets(&mut self, offsets: Range<usize>) { 148 self.get_or_init_info().offsets = Some(offsets); 149 } 150 151 pub(crate) fn set_info_oneway_node(&mut self, oneway_node: DArc<Node>) { 152 self.get_or_init_info().oneway_node = Some(oneway_node); 153 } 154 155 pub(crate) fn set_info_clear_on_drop(&mut self) { 156 self.get_or_init_info().clear_on_free = true; 157 } 158 159 pub(crate) fn set_info_target_node(&mut self, target_node: NodeRef) { 160 self.get_or_init_info().target_node = Some(target_node); 161 } 162 163 /// Reserve enough space to push at least `num_fds` fds. 164 pub(crate) fn info_add_fd_reserve(&mut self, num_fds: usize) -> Result { 165 self.get_or_init_info() 166 .file_list 167 .files_to_translate 168 .reserve(num_fds, GFP_KERNEL)?; 169 170 Ok(()) 171 } 172 173 pub(crate) fn info_add_fd( 174 &mut self, 175 file: ARef<File>, 176 buffer_offset: usize, 177 close_on_free: bool, 178 ) -> Result { 179 self.get_or_init_info().file_list.files_to_translate.push( 180 FileEntry { 181 file, 182 buffer_offset, 183 close_on_free, 184 }, 185 GFP_KERNEL, 186 )?; 187 188 Ok(()) 189 } 190 191 pub(crate) fn set_info_close_on_free(&mut self, cof: FdsCloseOnFree) { 192 self.get_or_init_info().file_list.close_on_free = cof.0; 193 } 194 195 pub(crate) fn translate_fds(&mut self) -> Result<TranslatedFds> { 196 let file_list = match self.allocation_info.as_mut() { 197 Some(info) => &mut info.file_list, 198 None => return Ok(TranslatedFds::new()), 199 }; 200 201 let files = core::mem::take(&mut file_list.files_to_translate); 202 203 let num_close_on_free = files.iter().filter(|entry| entry.close_on_free).count(); 204 let mut close_on_free = KVec::with_capacity(num_close_on_free, GFP_KERNEL)?; 205 206 let mut reservations = KVec::with_capacity(files.len(), GFP_KERNEL)?; 207 for file_info in files { 208 let res = FileDescriptorReservation::get_unused_fd_flags(bindings::O_CLOEXEC)?; 209 let fd = res.reserved_fd(); 210 self.write::<u32>(file_info.buffer_offset, &fd)?; 211 212 reservations.push( 213 Reservation { 214 res, 215 file: file_info.file, 216 }, 217 GFP_KERNEL, 218 )?; 219 if file_info.close_on_free { 220 close_on_free.push(fd, GFP_KERNEL)?; 221 } 222 } 223 224 Ok(TranslatedFds { 225 reservations, 226 close_on_free: FdsCloseOnFree(close_on_free), 227 }) 228 } 229 230 /// Should the looper return to userspace when freeing this allocation? 231 pub(crate) fn looper_need_return_on_free(&self) -> bool { 232 // Closing fds involves pushing task_work for execution when we return to userspace. Hence, 233 // we should return to userspace asap if we are closing fds. 234 match self.allocation_info { 235 Some(ref info) => !info.file_list.close_on_free.is_empty(), 236 None => false, 237 } 238 } 239 } 240 241 impl Drop for Allocation { 242 fn drop(&mut self) { 243 if !self.free_on_drop { 244 return; 245 } 246 247 if let Some(mut info) = self.allocation_info.take() { 248 if let Some(oneway_node) = info.oneway_node.as_ref() { 249 oneway_node.pending_oneway_finished(); 250 } 251 252 info.target_node = None; 253 254 if let Some(offsets) = info.offsets.clone() { 255 let view = AllocationView::new(self, offsets.start); 256 for i in offsets.step_by(size_of::<usize>()) { 257 if view.cleanup_object(i).is_err() { 258 pr_warn!("Error cleaning up object at offset {}\n", i) 259 } 260 } 261 } 262 263 for &fd in &info.file_list.close_on_free { 264 let closer = match DeferredFdCloser::new(GFP_KERNEL) { 265 Ok(closer) => closer, 266 Err(kernel::alloc::AllocError) => { 267 // Ignore allocation failures. 268 break; 269 } 270 }; 271 272 // Here, we ignore errors. The operation can fail if the fd is not valid, or if the 273 // method is called from a kthread. However, this is always called from a syscall, 274 // so the latter case cannot happen, and we don't care about the first case. 275 let _ = closer.close_fd(fd); 276 } 277 278 if info.clear_on_free { 279 if let Err(e) = self.fill_zero() { 280 pr_warn!("Failed to clear data on free: {:?}", e); 281 } 282 } 283 } 284 285 self.process.buffer_raw_free(self.ptr); 286 } 287 } 288 289 /// A wrapper around `Allocation` that is being created. 290 /// 291 /// If the allocation is destroyed while wrapped in this wrapper, then the allocation will be 292 /// considered to be part of a failed transaction. Successful transactions avoid that by calling 293 /// `success`, which skips the destructor. 294 #[repr(transparent)] 295 pub(crate) struct NewAllocation(pub(crate) Allocation); 296 297 impl NewAllocation { 298 pub(crate) fn success(self) -> Allocation { 299 // This skips the destructor. 300 // 301 // SAFETY: This type is `#[repr(transparent)]`, so the layout matches. 302 unsafe { core::mem::transmute(self) } 303 } 304 } 305 306 impl core::ops::Deref for NewAllocation { 307 type Target = Allocation; 308 fn deref(&self) -> &Allocation { 309 &self.0 310 } 311 } 312 313 impl core::ops::DerefMut for NewAllocation { 314 fn deref_mut(&mut self) -> &mut Allocation { 315 &mut self.0 316 } 317 } 318 319 /// A view into the beginning of an allocation. 320 /// 321 /// All attempts to read or write outside of the view will fail. To intentionally access outside of 322 /// this view, use the `alloc` field of this struct directly. 323 pub(crate) struct AllocationView<'a> { 324 pub(crate) alloc: &'a mut Allocation, 325 limit: usize, 326 } 327 328 impl<'a> AllocationView<'a> { 329 pub(crate) fn new(alloc: &'a mut Allocation, limit: usize) -> Self { 330 AllocationView { alloc, limit } 331 } 332 333 pub(crate) fn read<T: FromBytes>(&self, offset: usize) -> Result<T> { 334 if offset.checked_add(size_of::<T>()).ok_or(EINVAL)? > self.limit { 335 return Err(EINVAL); 336 } 337 self.alloc.read(offset) 338 } 339 340 pub(crate) fn write<T: AsBytes>(&self, offset: usize, obj: &T) -> Result { 341 if offset.checked_add(size_of::<T>()).ok_or(EINVAL)? > self.limit { 342 return Err(EINVAL); 343 } 344 self.alloc.write(offset, obj) 345 } 346 347 pub(crate) fn copy_into( 348 &self, 349 reader: &mut UserSliceReader, 350 offset: usize, 351 size: usize, 352 ) -> Result { 353 if offset.checked_add(size).ok_or(EINVAL)? > self.limit { 354 return Err(EINVAL); 355 } 356 self.alloc.copy_into(reader, offset, size) 357 } 358 359 pub(crate) fn transfer_binder_object( 360 &self, 361 offset: usize, 362 obj: &uapi::flat_binder_object, 363 strong: bool, 364 node_ref: NodeRef, 365 ) -> Result { 366 let mut newobj = FlatBinderObject::default(); 367 let node = node_ref.node.clone(); 368 if Arc::ptr_eq(&node_ref.node.owner, &self.alloc.process) { 369 // The receiving process is the owner of the node, so send it a binder object (instead 370 // of a handle). 371 let (ptr, cookie) = node.get_id(); 372 newobj.hdr.type_ = if strong { 373 BINDER_TYPE_BINDER 374 } else { 375 BINDER_TYPE_WEAK_BINDER 376 }; 377 newobj.flags = obj.flags; 378 newobj.__bindgen_anon_1.binder = ptr as _; 379 newobj.cookie = cookie as _; 380 self.write(offset, &newobj)?; 381 // Increment the user ref count on the node. It will be decremented as part of the 382 // destruction of the buffer, when we see a binder or weak-binder object. 383 node.update_refcount(true, 1, strong); 384 } else { 385 // The receiving process is different from the owner, so we need to insert a handle to 386 // the binder object. 387 let handle = self 388 .alloc 389 .process 390 .as_arc_borrow() 391 .insert_or_update_handle(node_ref, false)?; 392 newobj.hdr.type_ = if strong { 393 BINDER_TYPE_HANDLE 394 } else { 395 BINDER_TYPE_WEAK_HANDLE 396 }; 397 newobj.flags = obj.flags; 398 newobj.__bindgen_anon_1.handle = handle; 399 if self.write(offset, &newobj).is_err() { 400 // Decrement ref count on the handle we just created. 401 let _ = self 402 .alloc 403 .process 404 .as_arc_borrow() 405 .update_ref(handle, false, strong); 406 return Err(EINVAL); 407 } 408 } 409 410 Ok(()) 411 } 412 413 fn cleanup_object(&self, index_offset: usize) -> Result { 414 let offset = self.alloc.read(index_offset)?; 415 let header = self.read::<BinderObjectHeader>(offset)?; 416 match header.type_ { 417 BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => { 418 let obj = self.read::<FlatBinderObject>(offset)?; 419 let strong = header.type_ == BINDER_TYPE_BINDER; 420 // SAFETY: The type is `BINDER_TYPE_{WEAK_}BINDER`, so the `binder` field is 421 // populated. 422 let ptr = unsafe { obj.__bindgen_anon_1.binder }; 423 let cookie = obj.cookie; 424 self.alloc.process.update_node(ptr, cookie, strong); 425 Ok(()) 426 } 427 BINDER_TYPE_WEAK_HANDLE | BINDER_TYPE_HANDLE => { 428 let obj = self.read::<FlatBinderObject>(offset)?; 429 let strong = header.type_ == BINDER_TYPE_HANDLE; 430 // SAFETY: The type is `BINDER_TYPE_{WEAK_}HANDLE`, so the `handle` field is 431 // populated. 432 let handle = unsafe { obj.__bindgen_anon_1.handle }; 433 self.alloc 434 .process 435 .as_arc_borrow() 436 .update_ref(handle, false, strong) 437 } 438 _ => Ok(()), 439 } 440 } 441 } 442 443 /// A binder object as it is serialized. 444 /// 445 /// # Invariants 446 /// 447 /// All bytes must be initialized, and the value of `self.hdr.type_` must be one of the allowed 448 /// types. 449 #[repr(C)] 450 pub(crate) union BinderObject { 451 hdr: uapi::binder_object_header, 452 fbo: uapi::flat_binder_object, 453 fdo: uapi::binder_fd_object, 454 bbo: uapi::binder_buffer_object, 455 fdao: uapi::binder_fd_array_object, 456 } 457 458 /// A view into a `BinderObject` that can be used in a match statement. 459 pub(crate) enum BinderObjectRef<'a> { 460 Binder(&'a mut uapi::flat_binder_object), 461 Handle(&'a mut uapi::flat_binder_object), 462 Fd(&'a mut uapi::binder_fd_object), 463 Ptr(&'a mut uapi::binder_buffer_object), 464 Fda(&'a mut uapi::binder_fd_array_object), 465 } 466 467 impl BinderObject { 468 pub(crate) fn read_from(reader: &mut UserSliceReader) -> Result<BinderObject> { 469 let object = Self::read_from_inner(|slice| { 470 let read_len = usize::min(slice.len(), reader.len()); 471 reader.clone_reader().read_slice(&mut slice[..read_len])?; 472 Ok(()) 473 })?; 474 475 // If we used a object type smaller than the largest object size, then we've read more 476 // bytes than we needed to. However, we used `.clone_reader()` to avoid advancing the 477 // original reader. Now, we call `skip` so that the caller's reader is advanced by the 478 // right amount. 479 // 480 // The `skip` call fails if the reader doesn't have `size` bytes available. This could 481 // happen if the type header corresponds to an object type that is larger than the rest of 482 // the reader. 483 // 484 // Any extra bytes beyond the size of the object are inaccessible after this call, so 485 // reading them again from the `reader` later does not result in TOCTOU bugs. 486 reader.skip(object.size())?; 487 488 Ok(object) 489 } 490 491 /// Use the provided reader closure to construct a `BinderObject`. 492 /// 493 /// The closure should write the bytes for the object into the provided slice. 494 pub(crate) fn read_from_inner<R>(reader: R) -> Result<BinderObject> 495 where 496 R: FnOnce(&mut [u8; size_of::<BinderObject>()]) -> Result<()>, 497 { 498 let mut obj = MaybeUninit::<BinderObject>::zeroed(); 499 500 // SAFETY: The lengths of `BinderObject` and `[u8; size_of::<BinderObject>()]` are equal, 501 // and the byte array has an alignment requirement of one, so the pointer cast is okay. 502 // Additionally, `obj` was initialized to zeros, so the byte array will not be 503 // uninitialized. 504 (reader)(unsafe { &mut *obj.as_mut_ptr().cast() })?; 505 506 // SAFETY: The entire object is initialized, so accessing this field is safe. 507 let type_ = unsafe { obj.assume_init_ref().hdr.type_ }; 508 if Self::type_to_size(type_).is_none() { 509 // The value of `obj.hdr_type_` was invalid. 510 return Err(EINVAL); 511 } 512 513 // SAFETY: All bytes are initialized (since we zeroed them at the start) and we checked 514 // that `self.hdr.type_` is one of the allowed types, so the type invariants are satisfied. 515 unsafe { Ok(obj.assume_init()) } 516 } 517 518 pub(crate) fn as_ref(&mut self) -> BinderObjectRef<'_> { 519 use BinderObjectRef::*; 520 // SAFETY: The constructor ensures that all bytes of `self` are initialized, and all 521 // variants of this union accept all initialized bit patterns. 522 unsafe { 523 match self.hdr.type_ { 524 BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => Binder(&mut self.fbo), 525 BINDER_TYPE_WEAK_HANDLE | BINDER_TYPE_HANDLE => Handle(&mut self.fbo), 526 BINDER_TYPE_FD => Fd(&mut self.fdo), 527 BINDER_TYPE_PTR => Ptr(&mut self.bbo), 528 BINDER_TYPE_FDA => Fda(&mut self.fdao), 529 // SAFETY: By the type invariant, the value of `self.hdr.type_` cannot have any 530 // other value than the ones checked above. 531 _ => core::hint::unreachable_unchecked(), 532 } 533 } 534 } 535 536 pub(crate) fn size(&self) -> usize { 537 // SAFETY: The entire object is initialized, so accessing this field is safe. 538 let type_ = unsafe { self.hdr.type_ }; 539 540 // SAFETY: The type invariants guarantee that the type field is correct. 541 unsafe { Self::type_to_size(type_).unwrap_unchecked() } 542 } 543 544 fn type_to_size(type_: u32) -> Option<usize> { 545 match type_ { 546 BINDER_TYPE_WEAK_BINDER => Some(size_of::<uapi::flat_binder_object>()), 547 BINDER_TYPE_BINDER => Some(size_of::<uapi::flat_binder_object>()), 548 BINDER_TYPE_WEAK_HANDLE => Some(size_of::<uapi::flat_binder_object>()), 549 BINDER_TYPE_HANDLE => Some(size_of::<uapi::flat_binder_object>()), 550 BINDER_TYPE_FD => Some(size_of::<uapi::binder_fd_object>()), 551 BINDER_TYPE_PTR => Some(size_of::<uapi::binder_buffer_object>()), 552 BINDER_TYPE_FDA => Some(size_of::<uapi::binder_fd_array_object>()), 553 _ => None, 554 } 555 } 556 } 557 558 #[derive(Default)] 559 struct FileList { 560 files_to_translate: KVec<FileEntry>, 561 close_on_free: KVec<u32>, 562 } 563 564 struct FileEntry { 565 /// The file for which a descriptor will be created in the recipient process. 566 file: ARef<File>, 567 /// The offset in the buffer where the file descriptor is stored. 568 buffer_offset: usize, 569 /// Whether this fd should be closed when the allocation is freed. 570 close_on_free: bool, 571 } 572 573 pub(crate) struct TranslatedFds { 574 reservations: KVec<Reservation>, 575 /// If commit is called, then these fds should be closed. (If commit is not called, then they 576 /// shouldn't be closed.) 577 close_on_free: FdsCloseOnFree, 578 } 579 580 struct Reservation { 581 res: FileDescriptorReservation, 582 file: ARef<File>, 583 } 584 585 impl TranslatedFds { 586 pub(crate) fn new() -> Self { 587 Self { 588 reservations: KVec::new(), 589 close_on_free: FdsCloseOnFree(KVec::new()), 590 } 591 } 592 593 pub(crate) fn commit(self) -> FdsCloseOnFree { 594 for entry in self.reservations { 595 entry.res.fd_install(entry.file); 596 } 597 598 self.close_on_free 599 } 600 } 601 602 pub(crate) struct FdsCloseOnFree(KVec<u32>); 603