xref: /linux/drivers/android/binder/allocation.rs (revision 68a052239fc4b351e961f698b824f7654a346091)
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