Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/android/binder/allocation.rs
29520 views
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
604