// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2025 Google LLC.
//! This module defines the `Thread` type, which represents a userspace thread that is using
//! binder.
//!
//! The `Process` object stores all of the threads in an rb tree.
use kernel::{
bindings,
fs::{File, LocalFile},
list::{AtomicTracker, List, ListArc, ListLinks, TryNewListArc},
prelude::*,
security,
seq_file::SeqFile,
seq_print,
sync::poll::{PollCondVar, PollTable},
sync::{Arc, SpinLock},
task::Task,
types::ARef,
uaccess::UserSlice,
uapi,
};
use crate::{
allocation::{Allocation, AllocationView, BinderObject, BinderObjectRef, NewAllocation},
defs::*,
error::BinderResult,
process::{GetWorkOrRegister, Process},
ptr_align,
stats::GLOBAL_STATS,
transaction::Transaction,
BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverCode, DeliverToRead,
};
use core::{
mem::size_of,
sync::atomic::{AtomicU32, Ordering},
};
/// Stores the layout of the scatter-gather entries. This is used during the `translate_objects`
/// call and is discarded when it returns.
struct ScatterGatherState {
/// A struct that tracks the amount of unused buffer space.
unused_buffer_space: UnusedBufferSpace,
/// Scatter-gather entries to copy.
sg_entries: KVec<ScatterGatherEntry>,
/// Indexes into `sg_entries` corresponding to the last binder_buffer_object that
/// was processed and all of its ancestors. The array is in sorted order.
ancestors: KVec<usize>,
}
/// This entry specifies an additional buffer that should be copied using the scatter-gather
/// mechanism.
struct ScatterGatherEntry {
/// The index in the offset array of the BINDER_TYPE_PTR that this entry originates from.
obj_index: usize,
/// Offset in target buffer.
offset: usize,
/// User address in source buffer.
sender_uaddr: usize,
/// Number of bytes to copy.
length: usize,
/// The minimum offset of the next fixup in this buffer.
fixup_min_offset: usize,
/// The offsets within this buffer that contain pointers which should be translated.
pointer_fixups: KVec<PointerFixupEntry>,
}
/// This entry specifies that a fixup should happen at `target_offset` of the
/// buffer. If `skip` is nonzero, then the fixup is a `binder_fd_array_object`
/// and is applied later. Otherwise if `skip` is zero, then the size of the
/// fixup is `sizeof::<u64>()` and `pointer_value` is written to the buffer.
struct PointerFixupEntry {
/// The number of bytes to skip, or zero for a `binder_buffer_object` fixup.
skip: usize,
/// The translated pointer to write when `skip` is zero.
pointer_value: u64,
/// The offset at which the value should be written. The offset is relative
/// to the original buffer.
target_offset: usize,
}
/// Return type of `apply_and_validate_fixup_in_parent`.
struct ParentFixupInfo {
/// The index of the parent buffer in `sg_entries`.
parent_sg_index: usize,
/// The number of ancestors of the buffer.
///
/// The buffer is considered an ancestor of itself, so this is always at
/// least one.
num_ancestors: usize,
/// New value of `fixup_min_offset` if this fixup is applied.
new_min_offset: usize,
/// The offset of the fixup in the target buffer.
target_offset: usize,
}
impl ScatterGatherState {
/// Called when a `binder_buffer_object` or `binder_fd_array_object` tries
/// to access a region in its parent buffer. These accesses have various
/// restrictions, which this method verifies.
///
/// The `parent_offset` and `length` arguments describe the offset and
/// length of the access in the parent buffer.
///
/// # Detailed restrictions
///
/// Obviously the fixup must be in-bounds for the parent buffer.
///
/// For safety reasons, we only allow fixups inside a buffer to happen
/// at increasing offsets; additionally, we only allow fixup on the last
/// buffer object that was verified, or one of its parents.
///
/// Example of what is allowed:
///
/// A
/// B (parent = A, offset = 0)
/// C (parent = A, offset = 16)
/// D (parent = C, offset = 0)
/// E (parent = A, offset = 32) // min_offset is 16 (C.parent_offset)
///
/// Examples of what is not allowed:
///
/// Decreasing offsets within the same parent:
/// A
/// C (parent = A, offset = 16)
/// B (parent = A, offset = 0) // decreasing offset within A
///
/// Arcerring to a parent that wasn't the last object or any of its parents:
/// A
/// B (parent = A, offset = 0)
/// C (parent = A, offset = 0)
/// C (parent = A, offset = 16)
/// D (parent = B, offset = 0) // B is not A or any of A's parents
fn validate_parent_fixup(
&self,
parent: usize,
parent_offset: usize,
length: usize,
) -> Result<ParentFixupInfo> {
// Using `position` would also be correct, but `rposition` avoids
// quadratic running times.
let ancestors_i = self
.ancestors
.iter()
.copied()
.rposition(|sg_idx| self.sg_entries[sg_idx].obj_index == parent)
.ok_or(EINVAL)?;
|