| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752 |
- // SPDX-License-Identifier: GPL-2.0
- // Copyright (C) 2025 Google LLC.
- //! This module defines the `Process` type, which represents a process using a particular binder
- //! context.
- //!
- //! The `Process` object keeps track of all of the resources that this process owns in the binder
- //! context.
- //!
- //! There is one `Process` object for each binder fd that a process has opened, so processes using
- //! several binder contexts have several `Process` objects. This ensures that the contexts are
- //! fully separated.
- use core::mem::take;
- use kernel::{
- bindings,
- cred::Credential,
- error::Error,
- fs::file::{self, File},
- id_pool::IdPool,
- list::{List, ListArc, ListArcField, ListLinks},
- mm,
- prelude::*,
- rbtree::{self, RBTree, RBTreeNode, RBTreeNodeReservation},
- seq_file::SeqFile,
- seq_print,
- sync::poll::PollTable,
- sync::{
- aref::ARef,
- lock::{spinlock::SpinLockBackend, Guard},
- Arc, ArcBorrow, CondVar, CondVarTimeoutResult, Mutex, SpinLock, UniqueArc,
- },
- task::Task,
- uaccess::{UserSlice, UserSliceReader},
- uapi,
- workqueue::{self, Work},
- };
- use crate::{
- allocation::{Allocation, AllocationInfo, NewAllocation},
- context::Context,
- defs::*,
- error::{BinderError, BinderResult},
- node::{CouldNotDeliverCriticalIncrement, CritIncrWrapper, Node, NodeDeath, NodeRef},
- page_range::ShrinkablePageRange,
- range_alloc::{RangeAllocator, ReserveNew, ReserveNewArgs},
- stats::BinderStats,
- thread::{PushWorkRes, Thread},
- BinderfsProcFile, DArc, DLArc, DTRWrap, DeliverToRead,
- };
- #[path = "freeze.rs"]
- mod freeze;
- use self::freeze::{FreezeCookie, FreezeListener};
- struct Mapping {
- address: usize,
- alloc: RangeAllocator<AllocationInfo>,
- }
- impl Mapping {
- fn new(address: usize, size: usize) -> Self {
- Self {
- address,
- alloc: RangeAllocator::new(size),
- }
- }
- }
- // bitflags for defer_work.
- const PROC_DEFER_FLUSH: u8 = 1;
- const PROC_DEFER_RELEASE: u8 = 2;
- #[derive(Copy, Clone)]
- pub(crate) enum IsFrozen {
- Yes,
- No,
- InProgress,
- }
- impl IsFrozen {
- /// Whether incoming transactions should be rejected due to freeze.
- pub(crate) fn is_frozen(self) -> bool {
- match self {
- IsFrozen::Yes => true,
- IsFrozen::No => false,
- IsFrozen::InProgress => true,
- }
- }
- /// Whether freeze notifications consider this process frozen.
- pub(crate) fn is_fully_frozen(self) -> bool {
- match self {
- IsFrozen::Yes => true,
- IsFrozen::No => false,
- IsFrozen::InProgress => false,
- }
- }
- }
- /// The fields of `Process` protected by the spinlock.
- pub(crate) struct ProcessInner {
- is_manager: bool,
- pub(crate) is_dead: bool,
- threads: RBTree<i32, Arc<Thread>>,
- /// INVARIANT: Threads pushed to this list must be owned by this process.
- ready_threads: List<Thread>,
- nodes: RBTree<u64, DArc<Node>>,
- mapping: Option<Mapping>,
- work: List<DTRWrap<dyn DeliverToRead>>,
- delivered_deaths: List<DTRWrap<NodeDeath>, 2>,
- /// The number of requested threads that haven't registered yet.
- requested_thread_count: u32,
- /// The maximum number of threads used by the process thread pool.
- max_threads: u32,
- /// The number of threads the started and registered with the thread pool.
- started_thread_count: u32,
- /// Bitmap of deferred work to do.
- defer_work: u8,
- /// Number of transactions to be transmitted before processes in freeze_wait
- /// are woken up.
- outstanding_txns: u32,
- /// Process is frozen and unable to service binder transactions.
- pub(crate) is_frozen: IsFrozen,
- /// Process received sync transactions since last frozen.
- pub(crate) sync_recv: bool,
- /// Process received async transactions since last frozen.
- pub(crate) async_recv: bool,
- pub(crate) binderfs_file: Option<BinderfsProcFile>,
- /// Check for oneway spam
- oneway_spam_detection_enabled: bool,
- }
- impl ProcessInner {
- fn new() -> Self {
- Self {
- is_manager: false,
- is_dead: false,
- threads: RBTree::new(),
- ready_threads: List::new(),
- mapping: None,
- nodes: RBTree::new(),
- work: List::new(),
- delivered_deaths: List::new(),
- requested_thread_count: 0,
- max_threads: 0,
- started_thread_count: 0,
- defer_work: 0,
- outstanding_txns: 0,
- is_frozen: IsFrozen::No,
- sync_recv: false,
- async_recv: false,
- binderfs_file: None,
- oneway_spam_detection_enabled: false,
- }
- }
- /// Schedule the work item for execution on this process.
- ///
- /// If any threads are ready for work, then the work item is given directly to that thread and
- /// it is woken up. Otherwise, it is pushed to the process work list.
- ///
- /// This call can fail only if the process is dead. In this case, the work item is returned to
- /// the caller so that the caller can drop it after releasing the inner process lock. This is
- /// necessary since the destructor of `Transaction` will take locks that can't necessarily be
- /// taken while holding the inner process lock.
- pub(crate) fn push_work(
- &mut self,
- work: DLArc<dyn DeliverToRead>,
- ) -> Result<(), (BinderError, DLArc<dyn DeliverToRead>)> {
- // Try to find a ready thread to which to push the work.
- if let Some(thread) = self.ready_threads.pop_front() {
- // Push to thread while holding state lock. This prevents the thread from giving up
- // (for example, because of a signal) when we're about to deliver work.
- match thread.push_work(work) {
- PushWorkRes::Ok => Ok(()),
- PushWorkRes::FailedDead(work) => Err((BinderError::new_dead(), work)),
- }
- } else if self.is_dead {
- Err((BinderError::new_dead(), work))
- } else {
- let sync = work.should_sync_wakeup();
- // Didn't find a thread waiting for proc work; this can happen
- // in two scenarios:
- // 1. All threads are busy handling transactions
- // In that case, one of those threads should call back into
- // the kernel driver soon and pick up this work.
- // 2. Threads are using the (e)poll interface, in which case
- // they may be blocked on the waitqueue without having been
- // added to waiting_threads. For this case, we just iterate
- // over all threads not handling transaction work, and
- // wake them all up. We wake all because we don't know whether
- // a thread that called into (e)poll is handling non-binder
- // work currently.
- self.work.push_back(work);
- // Wake up polling threads, if any.
- for thread in self.threads.values() {
- thread.notify_if_poll_ready(sync);
- }
- Ok(())
- }
- }
- pub(crate) fn remove_node(&mut self, ptr: u64) {
- self.nodes.remove(&ptr);
- }
- /// Updates the reference count on the given node.
- pub(crate) fn update_node_refcount(
- &mut self,
- node: &DArc<Node>,
- inc: bool,
- strong: bool,
- count: usize,
- othread: Option<&Thread>,
- ) {
- let push = node.update_refcount_locked(inc, strong, count, self);
- // If we decided that we need to push work, push either to the process or to a thread if
- // one is specified.
- if let Some(node) = push {
- if let Some(thread) = othread {
- thread.push_work_deferred(node);
- } else {
- let _ = self.push_work(node);
- // Nothing to do: `push_work` may fail if the process is dead, but that's ok as in
- // that case, it doesn't care about the notification.
- }
- }
- }
- pub(crate) fn new_node_ref(
- &mut self,
- node: DArc<Node>,
- strong: bool,
- thread: Option<&Thread>,
- ) -> NodeRef {
- self.update_node_refcount(&node, true, strong, 1, thread);
- let strong_count = if strong { 1 } else { 0 };
- NodeRef::new(node, strong_count, 1 - strong_count)
- }
- pub(crate) fn new_node_ref_with_thread(
- &mut self,
- node: DArc<Node>,
- strong: bool,
- thread: &Thread,
- wrapper: Option<CritIncrWrapper>,
- ) -> Result<NodeRef, CouldNotDeliverCriticalIncrement> {
- let push = match wrapper {
- None => node
- .incr_refcount_allow_zero2one(strong, self)?
- .map(|node| node as _),
- Some(wrapper) => node.incr_refcount_allow_zero2one_with_wrapper(strong, wrapper, self),
- };
- if let Some(node) = push {
- thread.push_work_deferred(node);
- }
- let strong_count = if strong { 1 } else { 0 };
- Ok(NodeRef::new(node, strong_count, 1 - strong_count))
- }
- /// Returns an existing node with the given pointer and cookie, if one exists.
- ///
- /// Returns an error if a node with the given pointer but a different cookie exists.
- fn get_existing_node(&self, ptr: u64, cookie: u64) -> Result<Option<DArc<Node>>> {
- match self.nodes.get(&ptr) {
- None => Ok(None),
- Some(node) => {
- let (_, node_cookie) = node.get_id();
- if node_cookie == cookie {
- Ok(Some(node.clone()))
- } else {
- Err(EINVAL)
- }
- }
- }
- }
- fn register_thread(&mut self) -> bool {
- if self.requested_thread_count == 0 {
- return false;
- }
- self.requested_thread_count -= 1;
- self.started_thread_count += 1;
- true
- }
- /// Finds a delivered death notification with the given cookie, removes it from the thread's
- /// delivered list, and returns it.
- fn pull_delivered_death(&mut self, cookie: u64) -> Option<DArc<NodeDeath>> {
- let mut cursor = self.delivered_deaths.cursor_front();
- while let Some(next) = cursor.peek_next() {
- if next.cookie == cookie {
- return Some(next.remove().into_arc());
- }
- cursor.move_next();
- }
- None
- }
- pub(crate) fn death_delivered(&mut self, death: DArc<NodeDeath>) {
- if let Some(death) = ListArc::try_from_arc_or_drop(death) {
- self.delivered_deaths.push_back(death);
- } else {
- pr_warn!("Notification added to `delivered_deaths` twice.");
- }
- }
- pub(crate) fn add_outstanding_txn(&mut self) {
- self.outstanding_txns += 1;
- }
- fn txns_pending_locked(&self) -> bool {
- if self.outstanding_txns > 0 {
- return true;
- }
- for thread in self.threads.values() {
- if thread.has_current_transaction() {
- return true;
- }
- }
- false
- }
- }
- /// Used to keep track of a node that this process has a handle to.
- #[pin_data]
- pub(crate) struct NodeRefInfo {
- debug_id: usize,
- /// The refcount that this process owns to the node.
- node_ref: ListArcField<NodeRef, { Self::LIST_PROC }>,
- death: ListArcField<Option<DArc<NodeDeath>>, { Self::LIST_PROC }>,
- /// Cookie of the active freeze listener for this node.
- freeze: ListArcField<Option<FreezeCookie>, { Self::LIST_PROC }>,
- /// Used to store this `NodeRefInfo` in the node's `refs` list.
- #[pin]
- links: ListLinks<{ Self::LIST_NODE }>,
- /// The handle for this `NodeRefInfo`.
- handle: u32,
- /// The process that has a handle to the node.
- pub(crate) process: Arc<Process>,
- }
- impl NodeRefInfo {
- /// The id used for the `Node::refs` list.
- pub(crate) const LIST_NODE: u64 = 0x2da16350fb724a10;
- /// The id used for the `ListArc` in `ProcessNodeRefs`.
- const LIST_PROC: u64 = 0xd703a5263dcc8650;
- fn new(node_ref: NodeRef, handle: u32, process: Arc<Process>) -> impl PinInit<Self> {
- pin_init!(Self {
- debug_id: super::next_debug_id(),
- node_ref: ListArcField::new(node_ref),
- death: ListArcField::new(None),
- freeze: ListArcField::new(None),
- links <- ListLinks::new(),
- handle,
- process,
- })
- }
- kernel::list::define_list_arc_field_getter! {
- pub(crate) fn death(&mut self<{Self::LIST_PROC}>) -> &mut Option<DArc<NodeDeath>> { death }
- pub(crate) fn freeze(&mut self<{Self::LIST_PROC}>) -> &mut Option<FreezeCookie> { freeze }
- pub(crate) fn node_ref(&mut self<{Self::LIST_PROC}>) -> &mut NodeRef { node_ref }
- pub(crate) fn node_ref2(&self<{Self::LIST_PROC}>) -> &NodeRef { node_ref }
- }
- }
- kernel::list::impl_list_arc_safe! {
- impl ListArcSafe<{Self::LIST_NODE}> for NodeRefInfo { untracked; }
- impl ListArcSafe<{Self::LIST_PROC}> for NodeRefInfo { untracked; }
- }
- kernel::list::impl_list_item! {
- impl ListItem<{Self::LIST_NODE}> for NodeRefInfo {
- using ListLinks { self.links };
- }
- }
- /// Keeps track of references this process has to nodes owned by other processes.
- ///
- /// TODO: Currently, the rbtree requires two allocations per node reference, and two tree
- /// traversals to look up a node by `Node::global_id`. Once the rbtree is more powerful, these
- /// extra costs should be eliminated.
- struct ProcessNodeRefs {
- /// Used to look up nodes using the 32-bit id that this process knows it by.
- by_handle: RBTree<u32, ListArc<NodeRefInfo, { NodeRefInfo::LIST_PROC }>>,
- /// Used to quickly find unused ids in `by_handle`.
- handle_is_present: IdPool,
- /// Used to look up nodes without knowing their local 32-bit id. The usize is the address of
- /// the underlying `Node` struct as returned by `Node::global_id`.
- by_node: RBTree<usize, u32>,
- /// Used to look up a `FreezeListener` by cookie.
- ///
- /// There might be multiple freeze listeners for the same node, but at most one of them is
- /// active.
- freeze_listeners: RBTree<FreezeCookie, FreezeListener>,
- }
- impl ProcessNodeRefs {
- fn new() -> Self {
- Self {
- by_handle: RBTree::new(),
- handle_is_present: IdPool::new(),
- by_node: RBTree::new(),
- freeze_listeners: RBTree::new(),
- }
- }
- }
- use core::mem::offset_of;
- use kernel::bindings::rb_process_layout;
- pub(crate) const PROCESS_LAYOUT: rb_process_layout = rb_process_layout {
- arc_offset: Arc::<Process>::DATA_OFFSET,
- task: offset_of!(Process, task),
- };
- /// A process using binder.
- ///
- /// Strictly speaking, there can be multiple of these per process. There is one for each binder fd
- /// that a process has opened, so processes using several binder contexts have several `Process`
- /// objects. This ensures that the contexts are fully separated.
- #[pin_data]
- pub(crate) struct Process {
- pub(crate) ctx: Arc<Context>,
- // The task leader (process).
- pub(crate) task: ARef<Task>,
- // Credential associated with file when `Process` is created.
- pub(crate) cred: ARef<Credential>,
- #[pin]
- pub(crate) inner: SpinLock<ProcessInner>,
- #[pin]
- pub(crate) pages: ShrinkablePageRange,
- // Waitqueue of processes waiting for all outstanding transactions to be
- // processed.
- #[pin]
- freeze_wait: CondVar,
- // Node references are in a different lock to avoid recursive acquisition when
- // incrementing/decrementing a node in another process.
- #[pin]
- node_refs: Mutex<ProcessNodeRefs>,
- // Work node for deferred work item.
- #[pin]
- defer_work: Work<Process>,
- // Links for process list in Context.
- #[pin]
- links: ListLinks,
- pub(crate) stats: BinderStats,
- }
- kernel::impl_has_work! {
- impl HasWork<Process> for Process { self.defer_work }
- }
- kernel::list::impl_list_arc_safe! {
- impl ListArcSafe<0> for Process { untracked; }
- }
- kernel::list::impl_list_item! {
- impl ListItem<0> for Process {
- using ListLinks { self.links };
- }
- }
- impl workqueue::WorkItem for Process {
- type Pointer = Arc<Process>;
- fn run(me: Arc<Self>) {
- let defer;
- {
- let mut inner = me.inner.lock();
- defer = inner.defer_work;
- inner.defer_work = 0;
- }
- if defer & PROC_DEFER_FLUSH != 0 {
- me.deferred_flush();
- }
- if defer & PROC_DEFER_RELEASE != 0 {
- me.deferred_release();
- }
- }
- }
- impl Process {
- fn new(ctx: Arc<Context>, cred: ARef<Credential>) -> Result<Arc<Self>> {
- let current = kernel::current!();
- let process = Arc::pin_init::<Error>(
- try_pin_init!(Process {
- ctx,
- cred,
- inner <- kernel::new_spinlock!(ProcessInner::new(), "Process::inner"),
- pages <- ShrinkablePageRange::new(&super::BINDER_SHRINKER),
- node_refs <- kernel::new_mutex!(ProcessNodeRefs::new(), "Process::node_refs"),
- freeze_wait <- kernel::new_condvar!("Process::freeze_wait"),
- task: current.group_leader().into(),
- defer_work <- kernel::new_work!("Process::defer_work"),
- links <- ListLinks::new(),
- stats: BinderStats::new(),
- }),
- GFP_KERNEL,
- )?;
- process.ctx.register_process(process.clone())?;
- Ok(process)
- }
- pub(crate) fn pid_in_current_ns(&self) -> kernel::task::Pid {
- self.task.tgid_nr_ns(None)
- }
- #[inline(never)]
- pub(crate) fn debug_print_stats(&self, m: &SeqFile, ctx: &Context) -> Result<()> {
- seq_print!(m, "proc {}\n", self.pid_in_current_ns());
- seq_print!(m, "context {}\n", &*ctx.name);
- let inner = self.inner.lock();
- seq_print!(m, " threads: {}\n", inner.threads.iter().count());
- seq_print!(
- m,
- " requested threads: {}+{}/{}\n",
- inner.requested_thread_count,
- inner.started_thread_count,
- inner.max_threads,
- );
- if let Some(mapping) = &inner.mapping {
- seq_print!(
- m,
- " free oneway space: {}\n",
- mapping.alloc.free_oneway_space()
- );
- seq_print!(m, " buffers: {}\n", mapping.alloc.count_buffers());
- }
- seq_print!(
- m,
- " outstanding transactions: {}\n",
- inner.outstanding_txns
- );
- seq_print!(m, " nodes: {}\n", inner.nodes.iter().count());
- drop(inner);
- {
- let mut refs = self.node_refs.lock();
- let (mut count, mut weak, mut strong) = (0, 0, 0);
- for r in refs.by_handle.values_mut() {
- let node_ref = r.node_ref();
- let (nstrong, nweak) = node_ref.get_count();
- count += 1;
- weak += nweak;
- strong += nstrong;
- }
- seq_print!(m, " refs: {count} s {strong} w {weak}\n");
- }
- self.stats.debug_print(" ", m);
- Ok(())
- }
- #[inline(never)]
- pub(crate) fn debug_print(&self, m: &SeqFile, ctx: &Context, print_all: bool) -> Result<()> {
- seq_print!(m, "proc {}\n", self.pid_in_current_ns());
- seq_print!(m, "context {}\n", &*ctx.name);
- let mut all_threads = KVec::new();
- let mut all_nodes = KVec::new();
- loop {
- let inner = self.inner.lock();
- let num_threads = inner.threads.iter().count();
- let num_nodes = inner.nodes.iter().count();
- if all_threads.capacity() < num_threads || all_nodes.capacity() < num_nodes {
- drop(inner);
- all_threads.reserve(num_threads, GFP_KERNEL)?;
- all_nodes.reserve(num_nodes, GFP_KERNEL)?;
- continue;
- }
- for thread in inner.threads.values() {
- assert!(all_threads.len() < all_threads.capacity());
- let _ = all_threads.push(thread.clone(), GFP_ATOMIC);
- }
- for node in inner.nodes.values() {
- assert!(all_nodes.len() < all_nodes.capacity());
- let _ = all_nodes.push(node.clone(), GFP_ATOMIC);
- }
- break;
- }
- for thread in all_threads {
- thread.debug_print(m, print_all)?;
- }
- let mut inner = self.inner.lock();
- for node in all_nodes {
- if print_all || node.has_oneway_transaction(&mut inner) {
- node.full_debug_print(m, &mut inner)?;
- }
- }
- drop(inner);
- if print_all {
- let mut refs = self.node_refs.lock();
- for r in refs.by_handle.values_mut() {
- let node_ref = r.node_ref();
- let dead = node_ref.node.owner.inner.lock().is_dead;
- let (strong, weak) = node_ref.get_count();
- let debug_id = node_ref.node.debug_id;
- seq_print!(
- m,
- " ref {}: desc {} {}node {debug_id} s {strong} w {weak}",
- r.debug_id,
- r.handle,
- if dead { "dead " } else { "" }
- );
- }
- }
- let inner = self.inner.lock();
- for work in &inner.work {
- work.debug_print(m, " ", " pending transaction ")?;
- }
- for _death in &inner.delivered_deaths {
- seq_print!(m, " has delivered dead binder\n");
- }
- if let Some(mapping) = &inner.mapping {
- mapping.alloc.debug_print(m)?;
- }
- drop(inner);
- Ok(())
- }
- /// Attempts to fetch a work item from the process queue.
- pub(crate) fn get_work(&self) -> Option<DLArc<dyn DeliverToRead>> {
- self.inner.lock().work.pop_front()
- }
- /// Attempts to fetch a work item from the process queue. If none is available, it registers the
- /// given thread as ready to receive work directly.
- ///
- /// This must only be called when the thread is not participating in a transaction chain; when
- /// it is, work will always be delivered directly to the thread (and not through the process
- /// queue).
- pub(crate) fn get_work_or_register<'a>(
- &'a self,
- thread: &'a Arc<Thread>,
- ) -> GetWorkOrRegister<'a> {
- let mut inner = self.inner.lock();
- // Try to get work from the process queue.
- if let Some(work) = inner.work.pop_front() {
- return GetWorkOrRegister::Work(work);
- }
- // Register the thread as ready.
- GetWorkOrRegister::Register(Registration::new(thread, &mut inner))
- }
- fn get_current_thread(self: ArcBorrow<'_, Self>) -> Result<Arc<Thread>> {
- let id = {
- let current = kernel::current!();
- if !core::ptr::eq(current.group_leader(), &*self.task) {
- pr_err!("get_current_thread was called from the wrong process.");
- return Err(EINVAL);
- }
- current.pid()
- };
- {
- let inner = self.inner.lock();
- if let Some(thread) = inner.threads.get(&id) {
- return Ok(thread.clone());
- }
- }
- // Allocate a new `Thread` without holding any locks.
- let reservation = RBTreeNodeReservation::new(GFP_KERNEL)?;
- let ta: Arc<Thread> = Thread::new(id, self.into())?;
- let mut inner = self.inner.lock();
- match inner.threads.entry(id) {
- rbtree::Entry::Vacant(entry) => {
- entry.insert(ta.clone(), reservation);
- Ok(ta)
- }
- rbtree::Entry::Occupied(_entry) => {
- pr_err!("Cannot create two threads with the same id.");
- Err(EINVAL)
- }
- }
- }
- pub(crate) fn push_work(&self, work: DLArc<dyn DeliverToRead>) -> BinderResult {
- // If push_work fails, drop the work item outside the lock.
- let res = self.inner.lock().push_work(work);
- match res {
- Ok(()) => Ok(()),
- Err((err, work)) => {
- drop(work);
- Err(err)
- }
- }
- }
- fn set_as_manager(
- self: ArcBorrow<'_, Self>,
- info: Option<FlatBinderObject>,
- thread: &Thread,
- ) -> Result {
- let (ptr, cookie, flags) = if let Some(obj) = info {
- (
- // SAFETY: The object type for this ioctl is implicitly `BINDER_TYPE_BINDER`, so it
- // is safe to access the `binder` field.
- unsafe { obj.__bindgen_anon_1.binder },
- obj.cookie,
- obj.flags,
- )
- } else {
- (0, 0, 0)
- };
- let node_ref = self.get_node(ptr, cookie, flags as _, true, thread)?;
- let node = node_ref.node.clone();
- self.ctx.set_manager_node(node_ref)?;
- self.inner.lock().is_manager = true;
- // Force the state of the node to prevent the delivery of acquire/increfs.
- let mut owner_inner = node.owner.inner.lock();
- node.force_has_count(&mut owner_inner);
- Ok(())
- }
- fn get_node_inner(
- self: ArcBorrow<'_, Self>,
- ptr: u64,
- cookie: u64,
- flags: u32,
- strong: bool,
- thread: &Thread,
- wrapper: Option<CritIncrWrapper>,
- ) -> Result<Result<NodeRef, CouldNotDeliverCriticalIncrement>> {
- // Try to find an existing node.
- {
- let mut inner = self.inner.lock();
- if let Some(node) = inner.get_existing_node(ptr, cookie)? {
- return Ok(inner.new_node_ref_with_thread(node, strong, thread, wrapper));
- }
- }
- // Allocate the node before reacquiring the lock.
- let node = DTRWrap::arc_pin_init(Node::new(ptr, cookie, flags, self.into()))?.into_arc();
- let rbnode = RBTreeNode::new(ptr, node.clone(), GFP_KERNEL)?;
- let mut inner = self.inner.lock();
- if let Some(node) = inner.get_existing_node(ptr, cookie)? {
- return Ok(inner.new_node_ref_with_thread(node, strong, thread, wrapper));
- }
- inner.nodes.insert(rbnode);
- // This can only fail if someone has already pushed the node to a list, but we just created
- // it and still hold the lock, so it can't fail right now.
- let node_ref = inner
- .new_node_ref_with_thread(node, strong, thread, wrapper)
- .unwrap();
- Ok(Ok(node_ref))
- }
- pub(crate) fn get_node(
- self: ArcBorrow<'_, Self>,
- ptr: u64,
- cookie: u64,
- flags: u32,
- strong: bool,
- thread: &Thread,
- ) -> Result<NodeRef> {
- let mut wrapper = None;
- for _ in 0..2 {
- match self.get_node_inner(ptr, cookie, flags, strong, thread, wrapper) {
- Err(err) => return Err(err),
- Ok(Ok(node_ref)) => return Ok(node_ref),
- Ok(Err(CouldNotDeliverCriticalIncrement)) => {
- wrapper = Some(CritIncrWrapper::new()?);
- }
- }
- }
- // We only get a `CouldNotDeliverCriticalIncrement` error if `wrapper` is `None`, so the
- // loop should run at most twice.
- unreachable!()
- }
- pub(crate) fn insert_or_update_handle(
- self: ArcBorrow<'_, Process>,
- node_ref: NodeRef,
- is_manager: bool,
- ) -> Result<u32> {
- {
- let mut refs = self.node_refs.lock();
- // Do a lookup before inserting.
- if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) {
- let handle = *handle_ref;
- let info = refs.by_handle.get_mut(&handle).unwrap();
- info.node_ref().absorb(node_ref);
- return Ok(handle);
- }
- }
- // Reserve memory for tree nodes.
- let reserve1 = RBTreeNodeReservation::new(GFP_KERNEL)?;
- let reserve2 = RBTreeNodeReservation::new(GFP_KERNEL)?;
- let info = UniqueArc::new_uninit(GFP_KERNEL)?;
- let mut refs_lock = self.node_refs.lock();
- let mut refs = &mut *refs_lock;
- let (unused_id, by_handle_slot) = loop {
- // ID 0 may only be used by the manager.
- let start = if is_manager { 0 } else { 1 };
- if let Some(res) = refs.handle_is_present.find_unused_id(start) {
- match refs.by_handle.entry(res.as_u32()) {
- rbtree::Entry::Vacant(entry) => break (res, entry),
- rbtree::Entry::Occupied(_) => {
- pr_err!("Detected mismatch between handle_is_present and by_handle");
- res.acquire();
- kernel::warn_on!(true);
- return Err(EINVAL);
- }
- }
- }
- let grow_request = refs.handle_is_present.grow_request().ok_or(ENOMEM)?;
- drop(refs_lock);
- let resizer = grow_request.realloc(GFP_KERNEL)?;
- refs_lock = self.node_refs.lock();
- refs = &mut *refs_lock;
- refs.handle_is_present.grow(resizer);
- };
- let handle = unused_id.as_u32();
- // Do a lookup again as node may have been inserted before the lock was reacquired.
- if let Some(handle_ref) = refs.by_node.get(&node_ref.node.global_id()) {
- let handle = *handle_ref;
- let info = refs.by_handle.get_mut(&handle).unwrap();
- info.node_ref().absorb(node_ref);
- return Ok(handle);
- }
- let gid = node_ref.node.global_id();
- let (info_proc, info_node) = {
- let info_init = NodeRefInfo::new(node_ref, handle, self.into());
- match info.pin_init_with(info_init) {
- Ok(info) => ListArc::pair_from_pin_unique(info),
- // error is infallible
- Err(err) => match err {},
- }
- };
- // Ensure the process is still alive while we insert a new reference.
- //
- // This releases the lock before inserting the nodes, but since `is_dead` is set as the
- // first thing in `deferred_release`, process cleanup will not miss the items inserted into
- // `refs` below.
- if self.inner.lock().is_dead {
- return Err(ESRCH);
- }
- // SAFETY: `info_proc` and `info_node` reference the same node, so we are inserting
- // `info_node` into the right node's `refs` list.
- unsafe { info_proc.node_ref2().node.insert_node_info(info_node) };
- refs.by_node.insert(reserve1.into_node(gid, handle));
- by_handle_slot.insert(info_proc, reserve2);
- unused_id.acquire();
- Ok(handle)
- }
- pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult<NodeRef> {
- // When handle is zero, try to get the context manager.
- if handle == 0 {
- Ok(self.ctx.get_manager_node(true)?)
- } else {
- Ok(self.get_node_from_handle(handle, true)?)
- }
- }
- pub(crate) fn get_node_from_handle(&self, handle: u32, strong: bool) -> Result<NodeRef> {
- self.node_refs
- .lock()
- .by_handle
- .get_mut(&handle)
- .ok_or(ENOENT)?
- .node_ref()
- .clone(strong)
- }
- pub(crate) fn remove_from_delivered_deaths(&self, death: &DArc<NodeDeath>) {
- let mut inner = self.inner.lock();
- // SAFETY: By the invariant on the `delivered_links` field, this is the right linked list.
- let removed = unsafe { inner.delivered_deaths.remove(death) };
- drop(inner);
- drop(removed);
- }
- pub(crate) fn update_ref(
- self: ArcBorrow<'_, Process>,
- handle: u32,
- inc: bool,
- strong: bool,
- ) -> Result {
- if inc && handle == 0 {
- if let Ok(node_ref) = self.ctx.get_manager_node(strong) {
- if core::ptr::eq(&*self, &*node_ref.node.owner) {
- return Err(EINVAL);
- }
- let _ = self.insert_or_update_handle(node_ref, true);
- return Ok(());
- }
- }
- // To preserve original binder behaviour, we only fail requests where the manager tries to
- // increment references on itself.
- let mut refs = self.node_refs.lock();
- if let Some(info) = refs.by_handle.get_mut(&handle) {
- if info.node_ref().update(inc, strong) {
- // Clean up death if there is one attached to this node reference.
- if let Some(death) = info.death().take() {
- death.set_cleared(true);
- self.remove_from_delivered_deaths(&death);
- }
- // Remove reference from process tables, and from the node's `refs` list.
- // SAFETY: We are removing the `NodeRefInfo` from the right node.
- unsafe { info.node_ref2().node.remove_node_info(info) };
- let id = info.node_ref().node.global_id();
- refs.by_handle.remove(&handle);
- refs.by_node.remove(&id);
- refs.handle_is_present.release_id(handle as usize);
- if let Some(shrink) = refs.handle_is_present.shrink_request() {
- drop(refs);
- // This intentionally ignores allocation failures.
- if let Ok(new_bitmap) = shrink.realloc(GFP_KERNEL) {
- refs = self.node_refs.lock();
- refs.handle_is_present.shrink(new_bitmap);
- }
- }
- }
- } else {
- // All refs are cleared in process exit, so this warning is expected in that case.
- if !self.inner.lock().is_dead {
- pr_warn!("{}: no such ref {handle}\n", self.pid_in_current_ns());
- }
- }
- Ok(())
- }
- /// Decrements the refcount of the given node, if one exists.
- pub(crate) fn update_node(&self, ptr: u64, cookie: u64, strong: bool) {
- let mut inner = self.inner.lock();
- if let Ok(Some(node)) = inner.get_existing_node(ptr, cookie) {
- inner.update_node_refcount(&node, false, strong, 1, None);
- }
- }
- pub(crate) fn inc_ref_done(&self, reader: &mut UserSliceReader, strong: bool) -> Result {
- let ptr = reader.read::<u64>()?;
- let cookie = reader.read::<u64>()?;
- let mut inner = self.inner.lock();
- if let Ok(Some(node)) = inner.get_existing_node(ptr, cookie) {
- if let Some(node) = node.inc_ref_done_locked(strong, &mut inner) {
- // This only fails if the process is dead.
- let _ = inner.push_work(node);
- }
- }
- Ok(())
- }
- pub(crate) fn buffer_alloc(
- self: &Arc<Self>,
- debug_id: usize,
- size: usize,
- is_oneway: bool,
- from_pid: i32,
- ) -> BinderResult<NewAllocation> {
- use kernel::page::PAGE_SIZE;
- let mut reserve_new_args = ReserveNewArgs {
- debug_id,
- size,
- is_oneway,
- pid: from_pid,
- ..ReserveNewArgs::default()
- };
- let (new_alloc, addr) = loop {
- let mut inner = self.inner.lock();
- let mapping = inner.mapping.as_mut().ok_or_else(BinderError::new_dead)?;
- let alloc_request = match mapping.alloc.reserve_new(reserve_new_args)? {
- ReserveNew::Success(new_alloc) => break (new_alloc, mapping.address),
- ReserveNew::NeedAlloc(request) => request,
- };
- drop(inner);
- // We need to allocate memory and then call `reserve_new` again.
- reserve_new_args = alloc_request.make_alloc()?;
- };
- let res = Allocation::new(
- self.clone(),
- debug_id,
- new_alloc.offset,
- size,
- addr + new_alloc.offset,
- new_alloc.oneway_spam_detected,
- );
- // This allocation will be marked as in use until the `Allocation` is used to free it.
- //
- // This method can't be called while holding a lock, so we release the lock first. It's
- // okay for several threads to use the method on the same index at the same time. In that
- // case, one of the calls will allocate the given page (if missing), and the other call
- // will wait for the other call to finish allocating the page.
- //
- // We will not call `stop_using_range` in parallel with this on the same page, because the
- // allocation can only be removed via the destructor of the `Allocation` object that we
- // currently own.
- match self.pages.use_range(
- new_alloc.offset / PAGE_SIZE,
- (new_alloc.offset + size).div_ceil(PAGE_SIZE),
- ) {
- Ok(()) => {}
- Err(err) => {
- pr_warn!("use_range failure {:?}", err);
- return Err(err.into());
- }
- }
- Ok(NewAllocation(res))
- }
- pub(crate) fn buffer_get(self: &Arc<Self>, ptr: usize) -> Option<Allocation> {
- let mut inner = self.inner.lock();
- let mapping = inner.mapping.as_mut()?;
- let offset = ptr.checked_sub(mapping.address)?;
- let (size, debug_id, odata) = mapping.alloc.reserve_existing(offset).ok()?;
- let mut alloc = Allocation::new(self.clone(), debug_id, offset, size, ptr, false);
- if let Some(data) = odata {
- alloc.set_info(data);
- }
- Some(alloc)
- }
- pub(crate) fn buffer_raw_free(&self, ptr: usize) {
- let mut inner = self.inner.lock();
- if let Some(ref mut mapping) = &mut inner.mapping {
- let offset = match ptr.checked_sub(mapping.address) {
- Some(offset) => offset,
- None => return,
- };
- let freed_range = match mapping.alloc.reservation_abort(offset) {
- Ok(freed_range) => freed_range,
- Err(_) => {
- pr_warn!(
- "Pointer {:x} failed to free, base = {:x}\n",
- ptr,
- mapping.address
- );
- return;
- }
- };
- // No more allocations in this range. Mark them as not in use.
- //
- // Must be done before we release the lock so that `use_range` is not used on these
- // indices until `stop_using_range` returns.
- self.pages
- .stop_using_range(freed_range.start_page_idx, freed_range.end_page_idx);
- }
- }
- pub(crate) fn buffer_make_freeable(&self, offset: usize, mut data: Option<AllocationInfo>) {
- let mut inner = self.inner.lock();
- if let Some(ref mut mapping) = &mut inner.mapping {
- if mapping.alloc.reservation_commit(offset, &mut data).is_err() {
- pr_warn!("Offset {} failed to be marked freeable\n", offset);
- }
- }
- }
- fn create_mapping(&self, vma: &mm::virt::VmaNew) -> Result {
- use kernel::page::PAGE_SIZE;
- let size = usize::min(vma.end() - vma.start(), bindings::SZ_4M as usize);
- let mapping = Mapping::new(vma.start(), size);
- let page_count = self.pages.register_with_vma(vma)?;
- if page_count * PAGE_SIZE != size {
- return Err(EINVAL);
- }
- // Save range allocator for later.
- self.inner.lock().mapping = Some(mapping);
- Ok(())
- }
- fn version(&self, data: UserSlice) -> Result {
- data.writer().write(&BinderVersion::current())
- }
- pub(crate) fn register_thread(&self) -> bool {
- self.inner.lock().register_thread()
- }
- fn remove_thread(&self, thread: Arc<Thread>) {
- self.inner.lock().threads.remove(&thread.id);
- thread.release();
- }
- fn set_max_threads(&self, max: u32) {
- self.inner.lock().max_threads = max;
- }
- fn set_oneway_spam_detection_enabled(&self, enabled: u32) {
- self.inner.lock().oneway_spam_detection_enabled = enabled != 0;
- }
- pub(crate) fn is_oneway_spam_detection_enabled(&self) -> bool {
- self.inner.lock().oneway_spam_detection_enabled
- }
- fn get_node_debug_info(&self, data: UserSlice) -> Result {
- let (mut reader, mut writer) = data.reader_writer();
- // Read the starting point.
- let ptr = reader.read::<BinderNodeDebugInfo>()?.ptr;
- let mut out = BinderNodeDebugInfo::default();
- {
- let inner = self.inner.lock();
- for (node_ptr, node) in &inner.nodes {
- if *node_ptr > ptr {
- node.populate_debug_info(&mut out, &inner);
- break;
- }
- }
- }
- writer.write(&out)
- }
- fn get_node_info_from_ref(&self, data: UserSlice) -> Result {
- let (mut reader, mut writer) = data.reader_writer();
- let mut out = reader.read::<BinderNodeInfoForRef>()?;
- if out.strong_count != 0
- || out.weak_count != 0
- || out.reserved1 != 0
- || out.reserved2 != 0
- || out.reserved3 != 0
- {
- return Err(EINVAL);
- }
- // Only the context manager is allowed to use this ioctl.
- if !self.inner.lock().is_manager {
- return Err(EPERM);
- }
- {
- let mut node_refs = self.node_refs.lock();
- let node_info = node_refs.by_handle.get_mut(&out.handle).ok_or(ENOENT)?;
- let node_ref = node_info.node_ref();
- let owner_inner = node_ref.node.owner.inner.lock();
- node_ref.node.populate_counts(&mut out, &owner_inner);
- }
- // Write the result back.
- writer.write(&out)
- }
- pub(crate) fn needs_thread(&self) -> bool {
- let mut inner = self.inner.lock();
- let ret = inner.requested_thread_count == 0
- && inner.ready_threads.is_empty()
- && inner.started_thread_count < inner.max_threads;
- if ret {
- inner.requested_thread_count += 1
- }
- ret
- }
- pub(crate) fn request_death(
- self: &Arc<Self>,
- reader: &mut UserSliceReader,
- thread: &Thread,
- ) -> Result {
- let handle: u32 = reader.read()?;
- let cookie: u64 = reader.read()?;
- // Queue BR_ERROR if we can't allocate memory for the death notification.
- let death = UniqueArc::new_uninit(GFP_KERNEL).inspect_err(|_| {
- thread.push_return_work(BR_ERROR);
- })?;
- let mut refs = self.node_refs.lock();
- let Some(info) = refs.by_handle.get_mut(&handle) else {
- pr_warn!("BC_REQUEST_DEATH_NOTIFICATION invalid ref {handle}\n");
- return Ok(());
- };
- // Nothing to do if there is already a death notification request for this handle.
- if info.death().is_some() {
- pr_warn!("BC_REQUEST_DEATH_NOTIFICATION death notification already set\n");
- return Ok(());
- }
- let death = {
- let death_init = NodeDeath::new(info.node_ref().node.clone(), self.clone(), cookie);
- match death.pin_init_with(death_init) {
- Ok(death) => death,
- // error is infallible
- Err(err) => match err {},
- }
- };
- // Register the death notification.
- {
- let owner = info.node_ref2().node.owner.clone();
- let mut owner_inner = owner.inner.lock();
- if owner_inner.is_dead {
- let death = Arc::from(death);
- *info.death() = Some(death.clone());
- drop(owner_inner);
- death.set_dead();
- } else {
- let death = ListArc::from(death);
- *info.death() = Some(death.clone_arc());
- info.node_ref().node.add_death(death, &mut owner_inner);
- }
- }
- Ok(())
- }
- pub(crate) fn clear_death(&self, reader: &mut UserSliceReader, thread: &Thread) -> Result {
- let handle: u32 = reader.read()?;
- let cookie: u64 = reader.read()?;
- let mut refs = self.node_refs.lock();
- let Some(info) = refs.by_handle.get_mut(&handle) else {
- pr_warn!("BC_CLEAR_DEATH_NOTIFICATION invalid ref {handle}\n");
- return Ok(());
- };
- let Some(death) = info.death().take() else {
- pr_warn!("BC_CLEAR_DEATH_NOTIFICATION death notification not active\n");
- return Ok(());
- };
- if death.cookie != cookie {
- *info.death() = Some(death);
- pr_warn!("BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch\n");
- return Ok(());
- }
- // Update state and determine if we need to queue a work item. We only need to do it when
- // the node is not dead or if the user already completed the death notification.
- if death.set_cleared(false) {
- if let Some(death) = ListArc::try_from_arc_or_drop(death) {
- let _ = thread.push_work_if_looper(death);
- }
- }
- Ok(())
- }
- pub(crate) fn dead_binder_done(&self, cookie: u64, thread: &Thread) {
- let death = self.inner.lock().pull_delivered_death(cookie);
- if let Some(death) = death {
- death.set_notification_done(thread);
- }
- }
- /// Locks the spinlock and move the `nodes` rbtree out.
- ///
- /// This allows you to iterate through `nodes` while also allowing you to give other parts of
- /// the codebase exclusive access to `ProcessInner`.
- pub(crate) fn lock_with_nodes(&self) -> WithNodes<'_> {
- let mut inner = self.inner.lock();
- WithNodes {
- nodes: take(&mut inner.nodes),
- inner,
- }
- }
- fn deferred_flush(&self) {
- let inner = self.inner.lock();
- for thread in inner.threads.values() {
- thread.exit_looper();
- }
- }
- fn deferred_release(self: Arc<Self>) {
- let is_manager = {
- let mut inner = self.inner.lock();
- inner.is_dead = true;
- inner.is_frozen = IsFrozen::No;
- inner.sync_recv = false;
- inner.async_recv = false;
- inner.is_manager
- };
- if is_manager {
- self.ctx.unset_manager_node();
- }
- self.ctx.deregister_process(&self);
- let binderfs_file = self.inner.lock().binderfs_file.take();
- drop(binderfs_file);
- // Release threads.
- let threads = {
- let mut inner = self.inner.lock();
- let threads = take(&mut inner.threads);
- let ready = take(&mut inner.ready_threads);
- drop(inner);
- drop(ready);
- for thread in threads.values() {
- thread.release();
- }
- threads
- };
- // Release nodes.
- {
- while let Some(node) = {
- let mut lock = self.inner.lock();
- lock.nodes.cursor_front_mut().map(|c| c.remove_current().1)
- } {
- node.to_key_value().1.release();
- }
- }
- // Clean up death listeners and remove nodes from external node info lists.
- for info in self.node_refs.lock().by_handle.values_mut() {
- // SAFETY: We are removing the `NodeRefInfo` from the right node.
- unsafe { info.node_ref2().node.remove_node_info(info) };
- // Remove all death notifications from the nodes (that belong to a different process).
- let death = if let Some(existing) = info.death().take() {
- existing
- } else {
- continue;
- };
- death.set_cleared(false);
- }
- // Clean up freeze listeners.
- let freeze_listeners = take(&mut self.node_refs.lock().freeze_listeners);
- for listener in freeze_listeners.values() {
- listener.on_process_exit(&self);
- }
- drop(freeze_listeners);
- // Release refs on foreign nodes.
- {
- let mut refs = self.node_refs.lock();
- let by_handle = take(&mut refs.by_handle);
- let by_node = take(&mut refs.by_node);
- drop(refs);
- drop(by_node);
- drop(by_handle);
- }
- // Cancel all pending work items.
- while let Some(work) = self.get_work() {
- work.into_arc().cancel();
- }
- // Clear delivered_deaths list.
- //
- // Scope ensures that MutexGuard is dropped while executing the body.
- while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } {
- drop(delivered_death);
- }
- // Free any resources kept alive by allocated buffers.
- let omapping = self.inner.lock().mapping.take();
- if let Some(mut mapping) = omapping {
- let address = mapping.address;
- mapping
- .alloc
- .take_for_each(|offset, size, debug_id, odata| {
- let ptr = offset + address;
- let mut alloc =
- Allocation::new(self.clone(), debug_id, offset, size, ptr, false);
- if let Some(data) = odata {
- alloc.set_info(data);
- }
- drop(alloc)
- });
- }
- // calls to synchronize_rcu() in thread drop will happen here
- drop(threads);
- }
- pub(crate) fn drop_outstanding_txn(&self) {
- let wake = {
- let mut inner = self.inner.lock();
- if inner.outstanding_txns == 0 {
- pr_err!("outstanding_txns underflow");
- return;
- }
- inner.outstanding_txns -= 1;
- inner.is_frozen.is_frozen() && inner.outstanding_txns == 0
- };
- if wake {
- self.freeze_wait.notify_all();
- }
- }
- pub(crate) fn ioctl_freeze(&self, info: &BinderFreezeInfo) -> Result {
- if info.enable == 0 {
- let msgs = self.prepare_freeze_messages()?;
- let mut inner = self.inner.lock();
- inner.sync_recv = false;
- inner.async_recv = false;
- inner.is_frozen = IsFrozen::No;
- drop(inner);
- msgs.send_messages();
- return Ok(());
- }
- let mut inner = self.inner.lock();
- inner.sync_recv = false;
- inner.async_recv = false;
- inner.is_frozen = IsFrozen::InProgress;
- if info.timeout_ms > 0 {
- let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms);
- while jiffies > 0 {
- if inner.outstanding_txns == 0 {
- break;
- }
- match self
- .freeze_wait
- .wait_interruptible_timeout(&mut inner, jiffies)
- {
- CondVarTimeoutResult::Signal { .. } => {
- inner.is_frozen = IsFrozen::No;
- return Err(ERESTARTSYS);
- }
- CondVarTimeoutResult::Woken { jiffies: remaining } => {
- jiffies = remaining;
- }
- CondVarTimeoutResult::Timeout => {
- jiffies = 0;
- }
- }
- }
- }
- if inner.txns_pending_locked() {
- inner.is_frozen = IsFrozen::No;
- Err(EAGAIN)
- } else {
- drop(inner);
- match self.prepare_freeze_messages() {
- Ok(batch) => {
- self.inner.lock().is_frozen = IsFrozen::Yes;
- batch.send_messages();
- Ok(())
- }
- Err(kernel::alloc::AllocError) => {
- self.inner.lock().is_frozen = IsFrozen::No;
- Err(ENOMEM)
- }
- }
- }
- }
- }
- fn get_frozen_status(data: UserSlice) -> Result {
- let (mut reader, mut writer) = data.reader_writer();
- let mut info = reader.read::<BinderFrozenStatusInfo>()?;
- info.sync_recv = 0;
- info.async_recv = 0;
- let mut found = false;
- for ctx in crate::context::get_all_contexts()? {
- ctx.for_each_proc(|proc| {
- if proc.task.pid() == info.pid as _ {
- found = true;
- let inner = proc.inner.lock();
- let txns_pending = inner.txns_pending_locked();
- info.async_recv |= inner.async_recv as u32;
- info.sync_recv |= inner.sync_recv as u32;
- info.sync_recv |= (txns_pending as u32) << 1;
- }
- });
- }
- if found {
- writer.write(&info)?;
- Ok(())
- } else {
- Err(EINVAL)
- }
- }
- fn ioctl_freeze(reader: &mut UserSliceReader) -> Result {
- let info = reader.read::<BinderFreezeInfo>()?;
- // Very unlikely for there to be more than 3, since a process normally uses at most binder and
- // hwbinder.
- let mut procs = KVec::with_capacity(3, GFP_KERNEL)?;
- let ctxs = crate::context::get_all_contexts()?;
- for ctx in ctxs {
- for proc in ctx.get_procs_with_pid(info.pid as i32)? {
- procs.push(proc, GFP_KERNEL)?;
- }
- }
- for proc in procs {
- proc.ioctl_freeze(&info)?;
- }
- Ok(())
- }
- /// The ioctl handler.
- impl Process {
- /// Ioctls that are write-only from the perspective of userspace.
- ///
- /// The kernel will only read from the pointer that userspace provided to us.
- fn ioctl_write_only(
- this: ArcBorrow<'_, Process>,
- _file: &File,
- cmd: u32,
- reader: &mut UserSliceReader,
- ) -> Result {
- let thread = this.get_current_thread()?;
- match cmd {
- uapi::BINDER_SET_MAX_THREADS => this.set_max_threads(reader.read()?),
- uapi::BINDER_THREAD_EXIT => this.remove_thread(thread),
- uapi::BINDER_SET_CONTEXT_MGR => this.set_as_manager(None, &thread)?,
- uapi::BINDER_SET_CONTEXT_MGR_EXT => {
- this.set_as_manager(Some(reader.read()?), &thread)?
- }
- uapi::BINDER_ENABLE_ONEWAY_SPAM_DETECTION => {
- this.set_oneway_spam_detection_enabled(reader.read()?)
- }
- uapi::BINDER_FREEZE => ioctl_freeze(reader)?,
- _ => return Err(EINVAL),
- }
- Ok(())
- }
- /// Ioctls that are read/write from the perspective of userspace.
- ///
- /// The kernel will both read from and write to the pointer that userspace provided to us.
- fn ioctl_write_read(
- this: ArcBorrow<'_, Process>,
- file: &File,
- cmd: u32,
- data: UserSlice,
- ) -> Result {
- let thread = this.get_current_thread()?;
- let blocking = (file.flags() & file::flags::O_NONBLOCK) == 0;
- match cmd {
- uapi::BINDER_WRITE_READ => thread.write_read(data, blocking)?,
- uapi::BINDER_GET_NODE_DEBUG_INFO => this.get_node_debug_info(data)?,
- uapi::BINDER_GET_NODE_INFO_FOR_REF => this.get_node_info_from_ref(data)?,
- uapi::BINDER_VERSION => this.version(data)?,
- uapi::BINDER_GET_FROZEN_INFO => get_frozen_status(data)?,
- uapi::BINDER_GET_EXTENDED_ERROR => thread.get_extended_error(data)?,
- _ => return Err(EINVAL),
- }
- Ok(())
- }
- }
- /// The file operations supported by `Process`.
- impl Process {
- pub(crate) fn open(ctx: ArcBorrow<'_, Context>, file: &File) -> Result<Arc<Process>> {
- Self::new(ctx.into(), ARef::from(file.cred()))
- }
- pub(crate) fn release(this: Arc<Process>, _file: &File) {
- let binderfs_file;
- let should_schedule;
- {
- let mut inner = this.inner.lock();
- should_schedule = inner.defer_work == 0;
- inner.defer_work |= PROC_DEFER_RELEASE;
- binderfs_file = inner.binderfs_file.take();
- }
- if should_schedule {
- // Ignore failures to schedule to the workqueue. Those just mean that we're already
- // scheduled for execution.
- let _ = workqueue::system().enqueue(this);
- }
- drop(binderfs_file);
- }
- pub(crate) fn flush(this: ArcBorrow<'_, Process>) -> Result {
- let should_schedule;
- {
- let mut inner = this.inner.lock();
- should_schedule = inner.defer_work == 0;
- inner.defer_work |= PROC_DEFER_FLUSH;
- }
- if should_schedule {
- // Ignore failures to schedule to the workqueue. Those just mean that we're already
- // scheduled for execution.
- let _ = workqueue::system().enqueue(Arc::from(this));
- }
- Ok(())
- }
- pub(crate) fn ioctl(this: ArcBorrow<'_, Process>, file: &File, cmd: u32, arg: usize) -> Result {
- use kernel::ioctl::{_IOC_DIR, _IOC_SIZE};
- use kernel::uapi::{_IOC_READ, _IOC_WRITE};
- crate::trace::trace_ioctl(cmd, arg);
- let user_slice = UserSlice::new(UserPtr::from_addr(arg), _IOC_SIZE(cmd));
- const _IOC_READ_WRITE: u32 = _IOC_READ | _IOC_WRITE;
- match _IOC_DIR(cmd) {
- _IOC_WRITE => Self::ioctl_write_only(this, file, cmd, &mut user_slice.reader()),
- _IOC_READ_WRITE => Self::ioctl_write_read(this, file, cmd, user_slice),
- _ => Err(EINVAL),
- }
- }
- pub(crate) fn mmap(
- this: ArcBorrow<'_, Process>,
- _file: &File,
- vma: &mm::virt::VmaNew,
- ) -> Result {
- // We don't allow mmap to be used in a different process.
- if !core::ptr::eq(kernel::current!().group_leader(), &*this.task) {
- return Err(EINVAL);
- }
- if vma.start() == 0 {
- return Err(EINVAL);
- }
- vma.try_clear_maywrite().map_err(|_| EPERM)?;
- vma.set_dontcopy();
- vma.set_mixedmap();
- // TODO: Set ops. We need to learn when the user unmaps so that we can stop using it.
- this.create_mapping(vma)
- }
- pub(crate) fn poll(
- this: ArcBorrow<'_, Process>,
- file: &File,
- table: PollTable<'_>,
- ) -> Result<u32> {
- let thread = this.get_current_thread()?;
- let (from_proc, mut mask) = thread.poll(file, table);
- if mask == 0 && from_proc && !this.inner.lock().work.is_empty() {
- mask |= bindings::POLLIN;
- }
- Ok(mask)
- }
- }
- /// Represents that a thread has registered with the `ready_threads` list of its process.
- ///
- /// The destructor of this type will unregister the thread from the list of ready threads.
- pub(crate) struct Registration<'a> {
- thread: &'a Arc<Thread>,
- }
- impl<'a> Registration<'a> {
- fn new(thread: &'a Arc<Thread>, guard: &mut Guard<'_, ProcessInner, SpinLockBackend>) -> Self {
- assert!(core::ptr::eq(&thread.process.inner, guard.lock_ref()));
- // INVARIANT: We are pushing this thread to the right `ready_threads` list.
- if let Ok(list_arc) = ListArc::try_from_arc(thread.clone()) {
- guard.ready_threads.push_front(list_arc);
- } else {
- // It is an error to hit this branch, and it should not be reachable. We try to do
- // something reasonable when the failure path happens. Most likely, the thread in
- // question will sleep forever.
- pr_err!("Same thread registered with `ready_threads` twice.");
- }
- Self { thread }
- }
- }
- impl Drop for Registration<'_> {
- fn drop(&mut self) {
- let mut inner = self.thread.process.inner.lock();
- // SAFETY: The thread has the invariant that we never push it to any other linked list than
- // the `ready_threads` list of its parent process. Therefore, the thread is either in that
- // list, or in no list.
- unsafe { inner.ready_threads.remove(self.thread) };
- }
- }
- pub(crate) struct WithNodes<'a> {
- pub(crate) inner: Guard<'a, ProcessInner, SpinLockBackend>,
- pub(crate) nodes: RBTree<u64, DArc<Node>>,
- }
- impl Drop for WithNodes<'_> {
- fn drop(&mut self) {
- core::mem::swap(&mut self.nodes, &mut self.inner.nodes);
- if self.nodes.iter().next().is_some() {
- pr_err!("nodes array was modified while using lock_with_nodes\n");
- }
- }
- }
- pub(crate) enum GetWorkOrRegister<'a> {
- Work(DLArc<dyn DeliverToRead>),
- Register(Registration<'a>),
- }
|