transaction.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2025 Google LLC.
  3. use kernel::{
  4. prelude::*,
  5. seq_file::SeqFile,
  6. seq_print,
  7. sync::atomic::{ordering::Relaxed, Atomic},
  8. sync::{Arc, SpinLock},
  9. task::Kuid,
  10. time::{Instant, Monotonic},
  11. types::ScopeGuard,
  12. };
  13. use crate::{
  14. allocation::{Allocation, TranslatedFds},
  15. defs::*,
  16. error::{BinderError, BinderResult},
  17. node::{Node, NodeRef},
  18. process::{Process, ProcessInner},
  19. ptr_align,
  20. thread::{PushWorkRes, Thread},
  21. BinderReturnWriter, DArc, DLArc, DTRWrap, DeliverToRead,
  22. };
  23. use core::mem::offset_of;
  24. use kernel::bindings::rb_transaction_layout;
  25. pub(crate) const TRANSACTION_LAYOUT: rb_transaction_layout = rb_transaction_layout {
  26. debug_id: offset_of!(Transaction, debug_id),
  27. code: offset_of!(Transaction, code),
  28. flags: offset_of!(Transaction, flags),
  29. from_thread: offset_of!(Transaction, from),
  30. to_proc: offset_of!(Transaction, to),
  31. target_node: offset_of!(Transaction, target_node),
  32. };
  33. #[pin_data(PinnedDrop)]
  34. pub(crate) struct Transaction {
  35. pub(crate) debug_id: usize,
  36. target_node: Option<DArc<Node>>,
  37. pub(crate) from_parent: Option<DArc<Transaction>>,
  38. pub(crate) from: Arc<Thread>,
  39. pub(crate) to: Arc<Process>,
  40. #[pin]
  41. allocation: SpinLock<Option<Allocation>>,
  42. is_outstanding: Atomic<bool>,
  43. code: u32,
  44. pub(crate) flags: u32,
  45. data_size: usize,
  46. offsets_size: usize,
  47. data_address: usize,
  48. sender_euid: Kuid,
  49. txn_security_ctx_off: Option<usize>,
  50. pub(crate) oneway_spam_detected: bool,
  51. start_time: Instant<Monotonic>,
  52. }
  53. kernel::list::impl_list_arc_safe! {
  54. impl ListArcSafe<0> for Transaction { untracked; }
  55. }
  56. impl Transaction {
  57. pub(crate) fn new(
  58. node_ref: NodeRef,
  59. from_parent: Option<DArc<Transaction>>,
  60. from: &Arc<Thread>,
  61. tr: &BinderTransactionDataSg,
  62. ) -> BinderResult<DLArc<Self>> {
  63. let debug_id = super::next_debug_id();
  64. let trd = &tr.transaction_data;
  65. let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0;
  66. let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0;
  67. let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None };
  68. let to = node_ref.node.owner.clone();
  69. let mut alloc = match from.copy_transaction_data(
  70. to.clone(),
  71. tr,
  72. debug_id,
  73. allow_fds,
  74. txn_security_ctx_off.as_mut(),
  75. ) {
  76. Ok(alloc) => alloc,
  77. Err(err) => {
  78. if !err.is_dead() {
  79. pr_warn!("Failure in copy_transaction_data: {:?}", err);
  80. }
  81. return Err(err);
  82. }
  83. };
  84. let oneway_spam_detected = alloc.oneway_spam_detected;
  85. if trd.flags & TF_ONE_WAY != 0 {
  86. if from_parent.is_some() {
  87. pr_warn!("Oneway transaction should not be in a transaction stack.");
  88. return Err(EINVAL.into());
  89. }
  90. alloc.set_info_oneway_node(node_ref.node.clone());
  91. }
  92. if trd.flags & TF_CLEAR_BUF != 0 {
  93. alloc.set_info_clear_on_drop();
  94. }
  95. let target_node = node_ref.node.clone();
  96. alloc.set_info_target_node(node_ref);
  97. let data_address = alloc.ptr;
  98. Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
  99. debug_id,
  100. target_node: Some(target_node),
  101. from_parent,
  102. sender_euid: from.process.task.euid(),
  103. from: from.clone(),
  104. to,
  105. code: trd.code,
  106. flags: trd.flags,
  107. data_size: trd.data_size as _,
  108. offsets_size: trd.offsets_size as _,
  109. data_address,
  110. allocation <- kernel::new_spinlock!(Some(alloc.success()), "Transaction::new"),
  111. is_outstanding: Atomic::new(false),
  112. txn_security_ctx_off,
  113. oneway_spam_detected,
  114. start_time: Instant::now(),
  115. }))?)
  116. }
  117. pub(crate) fn new_reply(
  118. from: &Arc<Thread>,
  119. to: Arc<Process>,
  120. tr: &BinderTransactionDataSg,
  121. allow_fds: bool,
  122. ) -> BinderResult<DLArc<Self>> {
  123. let debug_id = super::next_debug_id();
  124. let trd = &tr.transaction_data;
  125. let mut alloc = match from.copy_transaction_data(to.clone(), tr, debug_id, allow_fds, None)
  126. {
  127. Ok(alloc) => alloc,
  128. Err(err) => {
  129. pr_warn!("Failure in copy_transaction_data: {:?}", err);
  130. return Err(err);
  131. }
  132. };
  133. let oneway_spam_detected = alloc.oneway_spam_detected;
  134. if trd.flags & TF_CLEAR_BUF != 0 {
  135. alloc.set_info_clear_on_drop();
  136. }
  137. Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
  138. debug_id,
  139. target_node: None,
  140. from_parent: None,
  141. sender_euid: from.process.task.euid(),
  142. from: from.clone(),
  143. to,
  144. code: trd.code,
  145. flags: trd.flags,
  146. data_size: trd.data_size as _,
  147. offsets_size: trd.offsets_size as _,
  148. data_address: alloc.ptr,
  149. allocation <- kernel::new_spinlock!(Some(alloc.success()), "Transaction::new"),
  150. is_outstanding: Atomic::new(false),
  151. txn_security_ctx_off: None,
  152. oneway_spam_detected,
  153. start_time: Instant::now(),
  154. }))?)
  155. }
  156. #[inline(never)]
  157. pub(crate) fn debug_print_inner(&self, m: &SeqFile, prefix: &str) {
  158. seq_print!(
  159. m,
  160. "{}{}: from {}:{} to {} code {:x} flags {:x} elapsed {}ms",
  161. prefix,
  162. self.debug_id,
  163. self.from.process.task.pid(),
  164. self.from.id,
  165. self.to.task.pid(),
  166. self.code,
  167. self.flags,
  168. self.start_time.elapsed().as_millis(),
  169. );
  170. if let Some(target_node) = &self.target_node {
  171. seq_print!(m, " node {}", target_node.debug_id);
  172. }
  173. seq_print!(m, " size {}:{}\n", self.data_size, self.offsets_size);
  174. }
  175. /// Determines if the transaction is stacked on top of the given transaction.
  176. pub(crate) fn is_stacked_on(&self, onext: &Option<DArc<Self>>) -> bool {
  177. match (&self.from_parent, onext) {
  178. (None, None) => true,
  179. (Some(from_parent), Some(next)) => Arc::ptr_eq(from_parent, next),
  180. _ => false,
  181. }
  182. }
  183. /// Returns a pointer to the next transaction on the transaction stack, if there is one.
  184. pub(crate) fn clone_next(&self) -> Option<DArc<Self>> {
  185. Some(self.from_parent.as_ref()?.clone())
  186. }
  187. /// Searches in the transaction stack for a thread that belongs to the target process. This is
  188. /// useful when finding a target for a new transaction: if the node belongs to a process that
  189. /// is already part of the transaction stack, we reuse the thread.
  190. fn find_target_thread(&self) -> Option<Arc<Thread>> {
  191. let mut it = &self.from_parent;
  192. while let Some(transaction) = it {
  193. if Arc::ptr_eq(&transaction.from.process, &self.to) {
  194. return Some(transaction.from.clone());
  195. }
  196. it = &transaction.from_parent;
  197. }
  198. None
  199. }
  200. /// Searches in the transaction stack for a transaction originating at the given thread.
  201. pub(crate) fn find_from(&self, thread: &Thread) -> Option<&DArc<Transaction>> {
  202. let mut it = &self.from_parent;
  203. while let Some(transaction) = it {
  204. if core::ptr::eq(thread, transaction.from.as_ref()) {
  205. return Some(transaction);
  206. }
  207. it = &transaction.from_parent;
  208. }
  209. None
  210. }
  211. pub(crate) fn set_outstanding(&self, to_process: &mut ProcessInner) {
  212. // No race because this method is only called once.
  213. if !self.is_outstanding.load(Relaxed) {
  214. self.is_outstanding.store(true, Relaxed);
  215. to_process.add_outstanding_txn();
  216. }
  217. }
  218. /// Decrement `outstanding_txns` in `to` if it hasn't already been decremented.
  219. fn drop_outstanding_txn(&self) {
  220. // No race because this is called at most twice, and one of the calls are in the
  221. // destructor, which is guaranteed to not race with any other operations on the
  222. // transaction. It also cannot race with `set_outstanding`, since submission happens
  223. // before delivery.
  224. if self.is_outstanding.load(Relaxed) {
  225. self.is_outstanding.store(false, Relaxed);
  226. self.to.drop_outstanding_txn();
  227. }
  228. }
  229. /// Submits the transaction to a work queue. Uses a thread if there is one in the transaction
  230. /// stack, otherwise uses the destination process.
  231. ///
  232. /// Not used for replies.
  233. pub(crate) fn submit(self: DLArc<Self>) -> BinderResult {
  234. // Defined before `process_inner` so that the destructor runs after releasing the lock.
  235. let mut _t_outdated;
  236. let oneway = self.flags & TF_ONE_WAY != 0;
  237. let process = self.to.clone();
  238. let mut process_inner = process.inner.lock();
  239. self.set_outstanding(&mut process_inner);
  240. if oneway {
  241. if let Some(target_node) = self.target_node.clone() {
  242. crate::trace::trace_transaction(false, &self, None);
  243. if process_inner.is_frozen.is_frozen() {
  244. process_inner.async_recv = true;
  245. if self.flags & TF_UPDATE_TXN != 0 {
  246. if let Some(t_outdated) =
  247. target_node.take_outdated_transaction(&self, &mut process_inner)
  248. {
  249. // Save the transaction to be dropped after locks are released.
  250. _t_outdated = t_outdated;
  251. }
  252. }
  253. }
  254. match target_node.submit_oneway(self, &mut process_inner) {
  255. Ok(()) => {}
  256. Err((err, work)) => {
  257. drop(process_inner);
  258. // Drop work after releasing process lock.
  259. drop(work);
  260. return Err(err);
  261. }
  262. }
  263. if process_inner.is_frozen.is_frozen() {
  264. return Err(BinderError::new_frozen_oneway());
  265. } else {
  266. return Ok(());
  267. }
  268. } else {
  269. pr_err!("Failed to submit oneway transaction to node.");
  270. }
  271. }
  272. if process_inner.is_frozen.is_frozen() {
  273. process_inner.sync_recv = true;
  274. return Err(BinderError::new_frozen());
  275. }
  276. let res = if let Some(thread) = self.find_target_thread() {
  277. crate::trace::trace_transaction(false, &self, Some(&thread.task));
  278. match thread.push_work(self) {
  279. PushWorkRes::Ok => Ok(()),
  280. PushWorkRes::FailedDead(me) => Err((BinderError::new_dead(), me)),
  281. }
  282. } else {
  283. crate::trace::trace_transaction(false, &self, None);
  284. process_inner.push_work(self)
  285. };
  286. drop(process_inner);
  287. match res {
  288. Ok(()) => Ok(()),
  289. Err((err, work)) => {
  290. // Drop work after releasing process lock.
  291. drop(work);
  292. Err(err)
  293. }
  294. }
  295. }
  296. /// Check whether one oneway transaction can supersede another.
  297. pub(crate) fn can_replace(&self, old: &Transaction) -> bool {
  298. if self.from.process.task.pid() != old.from.process.task.pid() {
  299. return false;
  300. }
  301. if self.flags & old.flags & (TF_ONE_WAY | TF_UPDATE_TXN) != (TF_ONE_WAY | TF_UPDATE_TXN) {
  302. return false;
  303. }
  304. let target_node_match = match (self.target_node.as_ref(), old.target_node.as_ref()) {
  305. (None, None) => true,
  306. (Some(tn1), Some(tn2)) => Arc::ptr_eq(tn1, tn2),
  307. _ => false,
  308. };
  309. self.code == old.code && self.flags == old.flags && target_node_match
  310. }
  311. fn prepare_file_list(&self) -> Result<TranslatedFds> {
  312. let mut alloc = self.allocation.lock().take().ok_or(ESRCH)?;
  313. match alloc.translate_fds() {
  314. Ok(translated) => {
  315. *self.allocation.lock() = Some(alloc);
  316. Ok(translated)
  317. }
  318. Err(err) => {
  319. // Free the allocation eagerly.
  320. drop(alloc);
  321. Err(err)
  322. }
  323. }
  324. }
  325. }
  326. impl DeliverToRead for Transaction {
  327. fn do_work(
  328. self: DArc<Self>,
  329. thread: &Thread,
  330. writer: &mut BinderReturnWriter<'_>,
  331. ) -> Result<bool> {
  332. let send_failed_reply = ScopeGuard::new(|| {
  333. if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
  334. let reply = Err(BR_FAILED_REPLY);
  335. self.from.deliver_reply(reply, &self);
  336. }
  337. self.drop_outstanding_txn();
  338. });
  339. let files = if let Ok(list) = self.prepare_file_list() {
  340. list
  341. } else {
  342. // On failure to process the list, we send a reply back to the sender and ignore the
  343. // transaction on the recipient.
  344. return Ok(true);
  345. };
  346. let mut tr_sec = BinderTransactionDataSecctx::default();
  347. let tr = tr_sec.tr_data();
  348. if let Some(target_node) = &self.target_node {
  349. let (ptr, cookie) = target_node.get_id();
  350. tr.target.ptr = ptr as _;
  351. tr.cookie = cookie as _;
  352. };
  353. tr.code = self.code;
  354. tr.flags = self.flags;
  355. tr.data_size = self.data_size as _;
  356. tr.data.ptr.buffer = self.data_address as _;
  357. tr.offsets_size = self.offsets_size as _;
  358. if tr.offsets_size > 0 {
  359. tr.data.ptr.offsets = (self.data_address + ptr_align(self.data_size).unwrap()) as _;
  360. }
  361. tr.sender_euid = self.sender_euid.into_uid_in_current_ns();
  362. tr.sender_pid = 0;
  363. if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
  364. // Not a reply and not one-way.
  365. tr.sender_pid = self.from.process.pid_in_current_ns();
  366. }
  367. let code = if self.target_node.is_none() {
  368. BR_REPLY
  369. } else if self.txn_security_ctx_off.is_some() {
  370. BR_TRANSACTION_SEC_CTX
  371. } else {
  372. BR_TRANSACTION
  373. };
  374. // Write the transaction code and data to the user buffer.
  375. writer.write_code(code)?;
  376. if let Some(off) = self.txn_security_ctx_off {
  377. tr_sec.secctx = (self.data_address + off) as u64;
  378. writer.write_payload(&tr_sec)?;
  379. } else {
  380. writer.write_payload(&*tr)?;
  381. }
  382. let mut alloc = self.allocation.lock().take().ok_or(ESRCH)?;
  383. // Dismiss the completion of transaction with a failure. No failure paths are allowed from
  384. // here on out.
  385. send_failed_reply.dismiss();
  386. // Commit files, and set FDs in FDA to be closed on buffer free.
  387. let close_on_free = files.commit();
  388. alloc.set_info_close_on_free(close_on_free);
  389. // It is now the user's responsibility to clear the allocation.
  390. alloc.keep_alive();
  391. self.drop_outstanding_txn();
  392. // When this is not a reply and not a oneway transaction, update `current_transaction`. If
  393. // it's a reply, `current_transaction` has already been updated appropriately.
  394. if self.target_node.is_some() && tr_sec.transaction_data.flags & TF_ONE_WAY == 0 {
  395. thread.set_current_transaction(self);
  396. }
  397. Ok(false)
  398. }
  399. fn cancel(self: DArc<Self>) {
  400. let allocation = self.allocation.lock().take();
  401. drop(allocation);
  402. // If this is not a reply or oneway transaction, then send a dead reply.
  403. if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
  404. let reply = Err(BR_DEAD_REPLY);
  405. self.from.deliver_reply(reply, &self);
  406. }
  407. self.drop_outstanding_txn();
  408. }
  409. fn should_sync_wakeup(&self) -> bool {
  410. self.flags & TF_ONE_WAY == 0
  411. }
  412. fn debug_print(&self, m: &SeqFile, _prefix: &str, tprefix: &str) -> Result<()> {
  413. self.debug_print_inner(m, tprefix);
  414. Ok(())
  415. }
  416. }
  417. #[pinned_drop]
  418. impl PinnedDrop for Transaction {
  419. fn drop(self: Pin<&mut Self>) {
  420. self.drop_outstanding_txn();
  421. }
  422. }