Path: blob/master/drivers/android/binder/rust_binder_main.rs
29520 views
// SPDX-License-Identifier: GPL-2.012// Copyright (C) 2025 Google LLC.34//! Binder -- the Android IPC mechanism.5#![recursion_limit = "256"]6#![allow(7clippy::as_underscore,8clippy::ref_as_ptr,9clippy::ptr_as_ptr,10clippy::cast_lossless11)]1213use kernel::{14bindings::{self, seq_file},15fs::File,16list::{ListArc, ListArcSafe, ListLinksSelfPtr, TryNewListArc},17prelude::*,18seq_file::SeqFile,19seq_print,20sync::poll::PollTable,21sync::Arc,22task::Pid,23transmute::AsBytes,24types::ForeignOwnable,25uaccess::UserSliceWriter,26};2728use crate::{context::Context, page_range::Shrinker, process::Process, thread::Thread};2930use core::{31ptr::NonNull,32sync::atomic::{AtomicBool, AtomicUsize, Ordering},33};3435mod allocation;36mod context;37mod deferred_close;38mod defs;39mod error;40mod node;41mod page_range;42mod process;43mod range_alloc;44mod stats;45mod thread;46mod trace;47mod transaction;4849#[allow(warnings)] // generated bindgen code50mod binderfs {51use kernel::bindings::{dentry, inode};5253extern "C" {54pub fn init_rust_binderfs() -> kernel::ffi::c_int;55}56extern "C" {57pub fn rust_binderfs_create_proc_file(58nodp: *mut inode,59pid: kernel::ffi::c_int,60) -> *mut dentry;61}62extern "C" {63pub fn rust_binderfs_remove_file(dentry: *mut dentry);64}65pub type rust_binder_context = *mut kernel::ffi::c_void;66#[repr(C)]67#[derive(Copy, Clone)]68pub struct binder_device {69pub minor: kernel::ffi::c_int,70pub ctx: rust_binder_context,71}72impl Default for binder_device {73fn default() -> Self {74let mut s = ::core::mem::MaybeUninit::<Self>::uninit();75unsafe {76::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);77s.assume_init()78}79}80}81}8283module! {84type: BinderModule,85name: "rust_binder",86authors: ["Wedson Almeida Filho", "Alice Ryhl"],87description: "Android Binder",88license: "GPL",89}9091fn next_debug_id() -> usize {92static NEXT_DEBUG_ID: AtomicUsize = AtomicUsize::new(0);9394NEXT_DEBUG_ID.fetch_add(1, Ordering::Relaxed)95}9697/// Provides a single place to write Binder return values via the98/// supplied `UserSliceWriter`.99pub(crate) struct BinderReturnWriter<'a> {100writer: UserSliceWriter,101thread: &'a Thread,102}103104impl<'a> BinderReturnWriter<'a> {105fn new(writer: UserSliceWriter, thread: &'a Thread) -> Self {106BinderReturnWriter { writer, thread }107}108109/// Write a return code back to user space.110/// Should be a `BR_` constant from [`defs`] e.g. [`defs::BR_TRANSACTION_COMPLETE`].111fn write_code(&mut self, code: u32) -> Result {112stats::GLOBAL_STATS.inc_br(code);113self.thread.process.stats.inc_br(code);114self.writer.write(&code)115}116117/// Write something *other than* a return code to user space.118fn write_payload<T: AsBytes>(&mut self, payload: &T) -> Result {119self.writer.write(payload)120}121122fn len(&self) -> usize {123self.writer.len()124}125}126127/// Specifies how a type should be delivered to the read part of a BINDER_WRITE_READ ioctl.128///129/// When a value is pushed to the todo list for a process or thread, it is stored as a trait object130/// with the type `Arc<dyn DeliverToRead>`. Trait objects are a Rust feature that lets you131/// implement dynamic dispatch over many different types. This lets us store many different types132/// in the todo list.133trait DeliverToRead: ListArcSafe + Send + Sync {134/// Performs work. Returns true if remaining work items in the queue should be processed135/// immediately, or false if it should return to caller before processing additional work136/// items.137fn do_work(138self: DArc<Self>,139thread: &Thread,140writer: &mut BinderReturnWriter<'_>,141) -> Result<bool>;142143/// Cancels the given work item. This is called instead of [`DeliverToRead::do_work`] when work144/// won't be delivered.145fn cancel(self: DArc<Self>);146147/// Should we use `wake_up_interruptible_sync` or `wake_up_interruptible` when scheduling this148/// work item?149///150/// Generally only set to true for non-oneway transactions.151fn should_sync_wakeup(&self) -> bool;152153fn debug_print(&self, m: &SeqFile, prefix: &str, transaction_prefix: &str) -> Result<()>;154}155156// Wrapper around a `DeliverToRead` with linked list links.157#[pin_data]158struct DTRWrap<T: ?Sized> {159#[pin]160links: ListLinksSelfPtr<DTRWrap<dyn DeliverToRead>>,161#[pin]162wrapped: T,163}164kernel::list::impl_list_arc_safe! {165impl{T: ListArcSafe + ?Sized} ListArcSafe<0> for DTRWrap<T> {166tracked_by wrapped: T;167}168}169kernel::list::impl_list_item! {170impl ListItem<0> for DTRWrap<dyn DeliverToRead> {171using ListLinksSelfPtr { self.links };172}173}174175impl<T: ?Sized> core::ops::Deref for DTRWrap<T> {176type Target = T;177fn deref(&self) -> &T {178&self.wrapped179}180}181182type DArc<T> = kernel::sync::Arc<DTRWrap<T>>;183type DLArc<T> = kernel::list::ListArc<DTRWrap<T>>;184185impl<T: ListArcSafe> DTRWrap<T> {186fn new(val: impl PinInit<T>) -> impl PinInit<Self> {187pin_init!(Self {188links <- ListLinksSelfPtr::new(),189wrapped <- val,190})191}192193fn arc_try_new(val: T) -> Result<DLArc<T>, kernel::alloc::AllocError> {194ListArc::pin_init(195try_pin_init!(Self {196links <- ListLinksSelfPtr::new(),197wrapped: val,198}),199GFP_KERNEL,200)201.map_err(|_| kernel::alloc::AllocError)202}203204fn arc_pin_init(init: impl PinInit<T>) -> Result<DLArc<T>, kernel::error::Error> {205ListArc::pin_init(206try_pin_init!(Self {207links <- ListLinksSelfPtr::new(),208wrapped <- init,209}),210GFP_KERNEL,211)212}213}214215struct DeliverCode {216code: u32,217skip: AtomicBool,218}219220kernel::list::impl_list_arc_safe! {221impl ListArcSafe<0> for DeliverCode { untracked; }222}223224impl DeliverCode {225fn new(code: u32) -> Self {226Self {227code,228skip: AtomicBool::new(false),229}230}231232/// Disable this DeliverCode and make it do nothing.233///234/// This is used instead of removing it from the work list, since `LinkedList::remove` is235/// unsafe, whereas this method is not.236fn skip(&self) {237self.skip.store(true, Ordering::Relaxed);238}239}240241impl DeliverToRead for DeliverCode {242fn do_work(243self: DArc<Self>,244_thread: &Thread,245writer: &mut BinderReturnWriter<'_>,246) -> Result<bool> {247if !self.skip.load(Ordering::Relaxed) {248writer.write_code(self.code)?;249}250Ok(true)251}252253fn cancel(self: DArc<Self>) {}254255fn should_sync_wakeup(&self) -> bool {256false257}258259fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {260seq_print!(m, "{}", prefix);261if self.skip.load(Ordering::Relaxed) {262seq_print!(m, "(skipped) ");263}264if self.code == defs::BR_TRANSACTION_COMPLETE {265seq_print!(m, "transaction complete\n");266} else {267seq_print!(m, "transaction error: {}\n", self.code);268}269Ok(())270}271}272273fn ptr_align(value: usize) -> Option<usize> {274let size = core::mem::size_of::<usize>() - 1;275Some(value.checked_add(size)? & !size)276}277278// SAFETY: We call register in `init`.279static BINDER_SHRINKER: Shrinker = unsafe { Shrinker::new() };280281struct BinderModule {}282283impl kernel::Module for BinderModule {284fn init(_module: &'static kernel::ThisModule) -> Result<Self> {285// SAFETY: The module initializer never runs twice, so we only call this once.286unsafe { crate::context::CONTEXTS.init() };287288pr_warn!("Loaded Rust Binder.");289290BINDER_SHRINKER.register(kernel::c_str!("android-binder"))?;291292// SAFETY: The module is being loaded, so we can initialize binderfs.293unsafe { kernel::error::to_result(binderfs::init_rust_binderfs())? };294295Ok(Self {})296}297}298299/// Makes the inner type Sync.300#[repr(transparent)]301pub struct AssertSync<T>(T);302// SAFETY: Used only to insert `file_operations` into a global, which is safe.303unsafe impl<T> Sync for AssertSync<T> {}304305/// File operations that rust_binderfs.c can use.306#[no_mangle]307#[used]308pub static rust_binder_fops: AssertSync<kernel::bindings::file_operations> = {309// SAFETY: All zeroes is safe for the `file_operations` type.310let zeroed_ops = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };311312let ops = kernel::bindings::file_operations {313owner: THIS_MODULE.as_ptr(),314poll: Some(rust_binder_poll),315unlocked_ioctl: Some(rust_binder_unlocked_ioctl),316compat_ioctl: Some(rust_binder_compat_ioctl),317mmap: Some(rust_binder_mmap),318open: Some(rust_binder_open),319release: Some(rust_binder_release),320flush: Some(rust_binder_flush),321..zeroed_ops322};323AssertSync(ops)324};325326/// # Safety327/// Only called by binderfs.328#[no_mangle]329unsafe extern "C" fn rust_binder_new_context(330name: *const kernel::ffi::c_char,331) -> *mut kernel::ffi::c_void {332// SAFETY: The caller will always provide a valid c string here.333let name = unsafe { kernel::str::CStr::from_char_ptr(name) };334match Context::new(name) {335Ok(ctx) => Arc::into_foreign(ctx),336Err(_err) => core::ptr::null_mut(),337}338}339340/// # Safety341/// Only called by binderfs.342#[no_mangle]343unsafe extern "C" fn rust_binder_remove_context(device: *mut kernel::ffi::c_void) {344if !device.is_null() {345// SAFETY: The caller ensures that the `device` pointer came from a previous call to346// `rust_binder_new_device`.347let ctx = unsafe { Arc::<Context>::from_foreign(device) };348ctx.deregister();349drop(ctx);350}351}352353/// # Safety354/// Only called by binderfs.355unsafe extern "C" fn rust_binder_open(356inode: *mut bindings::inode,357file_ptr: *mut bindings::file,358) -> kernel::ffi::c_int {359// SAFETY: The `rust_binderfs.c` file ensures that `i_private` is set to a360// `struct binder_device`.361let device = unsafe { (*inode).i_private } as *const binderfs::binder_device;362363assert!(!device.is_null());364365// SAFETY: The `rust_binderfs.c` file ensures that `device->ctx` holds a binder context when366// using the rust binder fops.367let ctx = unsafe { Arc::<Context>::borrow((*device).ctx) };368369// SAFETY: The caller provides a valid file pointer to a new `struct file`.370let file = unsafe { File::from_raw_file(file_ptr) };371let process = match Process::open(ctx, file) {372Ok(process) => process,373Err(err) => return err.to_errno(),374};375376// SAFETY: This is an `inode` for a newly created binder file.377match unsafe { BinderfsProcFile::new(inode, process.task.pid()) } {378Ok(Some(file)) => process.inner.lock().binderfs_file = Some(file),379Ok(None) => { /* pid already exists */ }380Err(err) => return err.to_errno(),381}382383// SAFETY: This file is associated with Rust binder, so we own the `private_data` field.384unsafe { (*file_ptr).private_data = process.into_foreign() };3850386}387388/// # Safety389/// Only called by binderfs.390unsafe extern "C" fn rust_binder_release(391_inode: *mut bindings::inode,392file: *mut bindings::file,393) -> kernel::ffi::c_int {394// SAFETY: We previously set `private_data` in `rust_binder_open`.395let process = unsafe { Arc::<Process>::from_foreign((*file).private_data) };396// SAFETY: The caller ensures that the file is valid.397let file = unsafe { File::from_raw_file(file) };398Process::release(process, file);3990400}401402/// # Safety403/// Only called by binderfs.404unsafe extern "C" fn rust_binder_compat_ioctl(405file: *mut bindings::file,406cmd: kernel::ffi::c_uint,407arg: kernel::ffi::c_ulong,408) -> kernel::ffi::c_long {409// SAFETY: We previously set `private_data` in `rust_binder_open`.410let f = unsafe { Arc::<Process>::borrow((*file).private_data) };411// SAFETY: The caller ensures that the file is valid.412match Process::compat_ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) {413Ok(()) => 0,414Err(err) => err.to_errno() as isize,415}416}417418/// # Safety419/// Only called by binderfs.420unsafe extern "C" fn rust_binder_unlocked_ioctl(421file: *mut bindings::file,422cmd: kernel::ffi::c_uint,423arg: kernel::ffi::c_ulong,424) -> kernel::ffi::c_long {425// SAFETY: We previously set `private_data` in `rust_binder_open`.426let f = unsafe { Arc::<Process>::borrow((*file).private_data) };427// SAFETY: The caller ensures that the file is valid.428match Process::ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) {429Ok(()) => 0,430Err(err) => err.to_errno() as isize,431}432}433434/// # Safety435/// Only called by binderfs.436unsafe extern "C" fn rust_binder_mmap(437file: *mut bindings::file,438vma: *mut bindings::vm_area_struct,439) -> kernel::ffi::c_int {440// SAFETY: We previously set `private_data` in `rust_binder_open`.441let f = unsafe { Arc::<Process>::borrow((*file).private_data) };442// SAFETY: The caller ensures that the vma is valid.443let area = unsafe { kernel::mm::virt::VmaNew::from_raw(vma) };444// SAFETY: The caller ensures that the file is valid.445match Process::mmap(f, unsafe { File::from_raw_file(file) }, area) {446Ok(()) => 0,447Err(err) => err.to_errno(),448}449}450451/// # Safety452/// Only called by binderfs.453unsafe extern "C" fn rust_binder_poll(454file: *mut bindings::file,455wait: *mut bindings::poll_table_struct,456) -> bindings::__poll_t {457// SAFETY: We previously set `private_data` in `rust_binder_open`.458let f = unsafe { Arc::<Process>::borrow((*file).private_data) };459// SAFETY: The caller ensures that the file is valid.460let fileref = unsafe { File::from_raw_file(file) };461// SAFETY: The caller ensures that the `PollTable` is valid.462match Process::poll(f, fileref, unsafe { PollTable::from_raw(wait) }) {463Ok(v) => v,464Err(_) => bindings::POLLERR,465}466}467468/// # Safety469/// Only called by binderfs.470unsafe extern "C" fn rust_binder_flush(471file: *mut bindings::file,472_id: bindings::fl_owner_t,473) -> kernel::ffi::c_int {474// SAFETY: We previously set `private_data` in `rust_binder_open`.475let f = unsafe { Arc::<Process>::borrow((*file).private_data) };476match Process::flush(f) {477Ok(()) => 0,478Err(err) => err.to_errno(),479}480}481482/// # Safety483/// Only called by binderfs.484#[no_mangle]485unsafe extern "C" fn rust_binder_stats_show(486ptr: *mut seq_file,487_: *mut kernel::ffi::c_void,488) -> kernel::ffi::c_int {489// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which490// this method is called.491let m = unsafe { SeqFile::from_raw(ptr) };492if let Err(err) = rust_binder_stats_show_impl(m) {493seq_print!(m, "failed to generate state: {:?}\n", err);494}4950496}497498/// # Safety499/// Only called by binderfs.500#[no_mangle]501unsafe extern "C" fn rust_binder_state_show(502ptr: *mut seq_file,503_: *mut kernel::ffi::c_void,504) -> kernel::ffi::c_int {505// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which506// this method is called.507let m = unsafe { SeqFile::from_raw(ptr) };508if let Err(err) = rust_binder_state_show_impl(m) {509seq_print!(m, "failed to generate state: {:?}\n", err);510}5110512}513514/// # Safety515/// Only called by binderfs.516#[no_mangle]517unsafe extern "C" fn rust_binder_proc_show(518ptr: *mut seq_file,519_: *mut kernel::ffi::c_void,520) -> kernel::ffi::c_int {521// SAFETY: Accessing the private field of `seq_file` is okay.522let pid = (unsafe { (*ptr).private }) as usize as Pid;523// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which524// this method is called.525let m = unsafe { SeqFile::from_raw(ptr) };526if let Err(err) = rust_binder_proc_show_impl(m, pid) {527seq_print!(m, "failed to generate state: {:?}\n", err);528}5290530}531532/// # Safety533/// Only called by binderfs.534#[no_mangle]535unsafe extern "C" fn rust_binder_transactions_show(536ptr: *mut seq_file,537_: *mut kernel::ffi::c_void,538) -> kernel::ffi::c_int {539// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which540// this method is called.541let m = unsafe { SeqFile::from_raw(ptr) };542if let Err(err) = rust_binder_transactions_show_impl(m) {543seq_print!(m, "failed to generate state: {:?}\n", err);544}5450546}547548fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result<()> {549seq_print!(m, "binder transactions:\n");550let contexts = context::get_all_contexts()?;551for ctx in contexts {552let procs = ctx.get_all_procs()?;553for proc in procs {554proc.debug_print(m, &ctx, false)?;555seq_print!(m, "\n");556}557}558Ok(())559}560561fn rust_binder_stats_show_impl(m: &SeqFile) -> Result<()> {562seq_print!(m, "binder stats:\n");563stats::GLOBAL_STATS.debug_print("", m);564let contexts = context::get_all_contexts()?;565for ctx in contexts {566let procs = ctx.get_all_procs()?;567for proc in procs {568proc.debug_print_stats(m, &ctx)?;569seq_print!(m, "\n");570}571}572Ok(())573}574575fn rust_binder_state_show_impl(m: &SeqFile) -> Result<()> {576seq_print!(m, "binder state:\n");577let contexts = context::get_all_contexts()?;578for ctx in contexts {579let procs = ctx.get_all_procs()?;580for proc in procs {581proc.debug_print(m, &ctx, true)?;582seq_print!(m, "\n");583}584}585Ok(())586}587588fn rust_binder_proc_show_impl(m: &SeqFile, pid: Pid) -> Result<()> {589seq_print!(m, "binder proc state:\n");590let contexts = context::get_all_contexts()?;591for ctx in contexts {592let procs = ctx.get_procs_with_pid(pid)?;593for proc in procs {594proc.debug_print(m, &ctx, true)?;595seq_print!(m, "\n");596}597}598Ok(())599}600601struct BinderfsProcFile(NonNull<bindings::dentry>);602603// SAFETY: Safe to drop any thread.604unsafe impl Send for BinderfsProcFile {}605606impl BinderfsProcFile {607/// # Safety608///609/// Takes an inode from a newly created binder file.610unsafe fn new(nodp: *mut bindings::inode, pid: i32) -> Result<Option<Self>> {611// SAFETY: The caller passes an `inode` for a newly created binder file.612let dentry = unsafe { binderfs::rust_binderfs_create_proc_file(nodp, pid) };613match kernel::error::from_err_ptr(dentry) {614Ok(dentry) => Ok(NonNull::new(dentry).map(Self)),615Err(err) if err == EEXIST => Ok(None),616Err(err) => Err(err),617}618}619}620621impl Drop for BinderfsProcFile {622fn drop(&mut self) {623// SAFETY: This is a dentry from `rust_binderfs_remove_file` that has not been deleted yet.624unsafe { binderfs::rust_binderfs_remove_file(self.0.as_ptr()) };625}626}627628629