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