projects/linux·blob master · refs

612 lines · 21.1 KiB

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