From: Greg Kroah-Hartman Date: Mon, 13 Jul 2026 13:15:12 +0000 (+0200) Subject: 7.1-stable patches X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ad1417b5d6d7118e996d2419bfa9eeb18ed97d3f;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: rust_binder-clear-freeze-listener-on-node-removal.patch rust_binder-fix-binder_get_extended_error.patch rust_binder-reject-context-manager-self-transaction.patch rust_binder-synchronize-rust-binder-stats-with-freeze-commands.patch rust_binder-use-a-u64-stride-when-cleaning-up-the-offsets-array.patch usb-typec-tcpci_rt1711h-unregister-tcpci-port-with-devres.patch usb-xhci-fix-sleep-in-atomic-context-in-xhci_free_streams.patch xhci-sideband-fix-ring-sg-table-pages-leak.patch --- diff --git a/queue-7.1/rust_binder-clear-freeze-listener-on-node-removal.patch b/queue-7.1/rust_binder-clear-freeze-listener-on-node-removal.patch new file mode 100644 index 0000000000..c5a71fd880 --- /dev/null +++ b/queue-7.1/rust_binder-clear-freeze-listener-on-node-removal.patch @@ -0,0 +1,115 @@ +From bc4a9828897871ff3e5a1f8a1d346decbf4ee95e Mon Sep 17 00:00:00 2001 +From: Alice Ryhl +Date: Fri, 3 Jul 2026 11:25:12 +0000 +Subject: rust_binder: clear freeze listener on node removal + +From: Alice Ryhl + +commit bc4a9828897871ff3e5a1f8a1d346decbf4ee95e upstream. + +Generally userspace is supposed to explicitly clear freeze listeners +before they drop the refcount on the node ref to zero, but there's +nothing forcing that. Currently, in this scenario the freeze listener +remains in the freeze_listeners rbtree and in the remote node's freeze +listener list, even though the ref for which the listener is registered +is gone. This could potentially lead to a memory leak due to a refcount +cycle. Thus, remove the freeze listener in this scenario. + +Cc: stable +Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") +Signed-off-by: Alice Ryhl +Link: https://patch.msgid.link/20260703-remove-freeze-on-remove-node-v3-1-6e0c4547af46@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/android/binder/freeze.rs | 11 +++++++++-- + drivers/android/binder/node.rs | 10 ++++++---- + drivers/android/binder/process.rs | 12 +++++++++++- + 3 files changed, 26 insertions(+), 7 deletions(-) + +--- a/drivers/android/binder/freeze.rs ++++ b/drivers/android/binder/freeze.rs +@@ -154,10 +154,17 @@ impl DeliverToRead for FreezeMessage { + } + + impl FreezeListener { +- pub(crate) fn on_process_exit(&self, proc: &Arc) { ++ /// Called when this freeze listener is cleared abnormally. ++ /// ++ /// This occurs either because the process exited or because the process dropped its last ++ /// refcount on the node ref without explicitly removing the freeze listener first. ++ /// ++ /// The returned `KVVec` is just a value that should be dropped outside of the lock. ++ pub(crate) fn on_process_cleanup(&self, proc: &Process) -> KVVec> { + if !self.is_clearing { +- self.node.remove_freeze_listener(proc); ++ return self.node.remove_freeze_listener(proc); + } ++ KVVec::new() + } + } + +--- a/drivers/android/binder/node.rs ++++ b/drivers/android/binder/node.rs +@@ -682,12 +682,13 @@ impl Node { + } + } + +- pub(crate) fn remove_freeze_listener(&self, p: &Arc) { +- let _unused_capacity; ++ pub(crate) fn remove_freeze_listener(&self, p: &Process) -> KVVec> { + let mut guard = self.owner.inner.lock(); + let inner = self.inner.access_mut(&mut guard); + let len = inner.freeze_list.len(); +- inner.freeze_list.retain(|proc| !Arc::ptr_eq(proc, p)); ++ inner ++ .freeze_list ++ .retain(|proc| !core::ptr::eq::(&**proc, p)); + if len == inner.freeze_list.len() { + pr_warn!( + "Could not remove freeze listener for {}\n", +@@ -695,8 +696,9 @@ impl Node { + ); + } + if inner.freeze_list.is_empty() { +- _unused_capacity = mem::take(&mut inner.freeze_list); ++ return mem::take(&mut inner.freeze_list); + } ++ KVVec::new() + } + + pub(crate) fn freeze_list<'a>(&'a self, guard: &'a ProcessInner) -> &'a [Arc] { +--- a/drivers/android/binder/process.rs ++++ b/drivers/android/binder/process.rs +@@ -946,6 +946,8 @@ impl Process { + + // To preserve original binder behaviour, we only fail requests where the manager tries to + // increment references on itself. ++ let _to_free_freeze_listener; ++ let _to_free_freeze_listener_cleanup; + let mut refs = self.node_refs.lock(); + if let Some(info) = refs.by_handle.get_mut(&handle) { + if info.node_ref().update(inc, strong) { +@@ -961,6 +963,14 @@ impl Process { + unsafe { info.node_ref2().node.remove_node_info(info) }; + + let id = info.node_ref().node.global_id(); ++ ++ if let Some(freeze) = *info.freeze() { ++ if let Some(fl) = refs.freeze_listeners.remove(&freeze) { ++ _to_free_freeze_listener_cleanup = fl.on_process_cleanup(&self); ++ _to_free_freeze_listener = fl; ++ } ++ } ++ + refs.by_handle.remove(&handle); + refs.by_node.remove(&id); + refs.handle_is_present.release_id(handle as usize); +@@ -1384,7 +1394,7 @@ impl Process { + // 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); ++ listener.on_process_cleanup(&self); + } + drop(freeze_listeners); + diff --git a/queue-7.1/rust_binder-fix-binder_get_extended_error.patch b/queue-7.1/rust_binder-fix-binder_get_extended_error.patch new file mode 100644 index 0000000000..585475a00c --- /dev/null +++ b/queue-7.1/rust_binder-fix-binder_get_extended_error.patch @@ -0,0 +1,277 @@ +From 77bfebf110773f5a0d6b5ff8110896adb2c9c335 Mon Sep 17 00:00:00 2001 +From: Alice Ryhl +Date: Fri, 5 Jun 2026 11:13:50 +0000 +Subject: rust_binder: fix BINDER_GET_EXTENDED_ERROR + +From: Alice Ryhl + +commit 77bfebf110773f5a0d6b5ff8110896adb2c9c335 upstream. + +This code currently copies the ExtendedError struct to the stack, +modifies the copy, and then doesn't modify the original. Thus, fix it. + +Furthermore, errors when replying must be delivered directly to the +remote thread, so update deliver_reply() to take an extended error +argument. + +Cc: stable +Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") +Signed-off-by: Alice Ryhl +Acked-by: Carlos Llamas +Link: https://patch.msgid.link/20260605-set-extended-error-v3-1-d60b69a75f97@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/android/binder/error.rs | 13 ++---- + drivers/android/binder/thread.rs | 65 ++++++++++++++++++++++++---------- + drivers/android/binder/transaction.rs | 15 +++---- + 3 files changed, 58 insertions(+), 35 deletions(-) + +--- a/drivers/android/binder/error.rs ++++ b/drivers/android/binder/error.rs +@@ -73,20 +73,17 @@ impl fmt::Debug for BinderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.reply { + BR_FAILED_REPLY => match self.source.as_ref() { +- Some(source) => f +- .debug_struct("BR_FAILED_REPLY") +- .field("source", source) +- .finish(), ++ Some(source) => source.fmt(f), + None => f.pad("BR_FAILED_REPLY"), + }, + BR_DEAD_REPLY => f.pad("BR_DEAD_REPLY"), + BR_FROZEN_REPLY => f.pad("BR_FROZEN_REPLY"), + BR_TRANSACTION_PENDING_FROZEN => f.pad("BR_TRANSACTION_PENDING_FROZEN"), + BR_TRANSACTION_COMPLETE => f.pad("BR_TRANSACTION_COMPLETE"), +- _ => f +- .debug_struct("BinderError") +- .field("reply", &self.reply) +- .finish(), ++ _ => match self.source.as_ref() { ++ Some(source) => source.fmt(f), ++ None => self.reply.fmt(f), ++ }, + } + } + } +--- a/drivers/android/binder/thread.rs ++++ b/drivers/android/binder/thread.rs +@@ -495,9 +495,16 @@ impl Thread { + Ok(()) + } + ++ pub(crate) fn clear_extended_error(&self, debug_id: usize) { ++ self.inner.lock().extended_error = ExtendedError::new(debug_id as u32, BR_OK, 0); ++ } ++ + pub(crate) fn get_extended_error(&self, data: UserSlice) -> Result { + let mut writer = data.writer(); +- let ee = self.inner.lock().extended_error; ++ let mut inner = self.inner.lock(); ++ let ee = inner.extended_error; ++ inner.extended_error = ExtendedError::new(0, BR_OK, 0); ++ drop(inner); + writer.write(&ee)?; + Ok(()) + } +@@ -1109,7 +1116,10 @@ impl Thread { + inner.pop_transaction_to_reply(thread.as_ref()) + } { + let reply = Err(BR_DEAD_REPLY); +- if !transaction.from.deliver_single_reply(reply, &transaction) { ++ if !transaction ++ .from ++ .deliver_single_reply(reply, &transaction, None) ++ { + break; + } + +@@ -1121,8 +1131,9 @@ impl Thread { + &self, + reply: Result, u32>, + transaction: &DArc, ++ extended_error: Option, + ) { +- if self.deliver_single_reply(reply, transaction) { ++ if self.deliver_single_reply(reply, transaction, extended_error) { + transaction.from.unwind_transaction_stack(); + } + } +@@ -1136,6 +1147,7 @@ impl Thread { + &self, + reply: Result, u32>, + transaction: &DArc, ++ extended_error: Option, + ) -> bool { + if let Ok(transaction) = &reply { + crate::trace::trace_transaction(true, transaction, Some(&self.task)); +@@ -1152,6 +1164,12 @@ impl Thread { + return true; + } + ++ if let Some(ee) = extended_error { ++ if inner.extended_error.command == BR_OK { ++ inner.extended_error = ee; ++ } ++ } ++ + match reply { + Ok(work) => { + inner.push_work(work); +@@ -1222,6 +1240,9 @@ impl Thread { + info.buffers_size = td.buffers_size as usize; + // SAFETY: Above `read` call initializes all bytes, so this union read is ok. + info.target_handle = unsafe { td.transaction_data.target.handle }; ++ ++ info.debug_id = super::next_debug_id(); ++ + Ok(()) + } + +@@ -1230,6 +1251,8 @@ impl Thread { + let mut info = TransactionInfo::zeroed(); + self.read_transaction_info(cmd, reader, &mut info)?; + ++ self.clear_extended_error(info.debug_id); ++ + let ret = if info.is_reply { + self.reply_inner(&mut info) + } else if info.is_oneway() { +@@ -1239,23 +1262,21 @@ impl Thread { + }; + + if let Err(err) = ret { +- if err.reply != BR_TRANSACTION_COMPLETE { +- info.reply = err.reply; +- } +- + self.push_return_work(err.reply); +- if let Some(source) = &err.source { +- info.errno = source.to_errno(); ++ if err.reply != BR_TRANSACTION_COMPLETE { + info.reply = err.reply; ++ if let Some(source) = &err.source { ++ info.errno = source.to_errno(); + +- { +- let mut ee = self.inner.lock().extended_error; +- ee.command = err.reply; +- ee.param = source.to_errno(); ++ { ++ let mut inner = self.inner.lock(); ++ inner.extended_error = ++ ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno()); ++ } + } + + pr_warn!( +- "{}:{} transaction to {} failed: {source:?}", ++ "{}:{} transaction to {} failed: {err:?}", + info.from_pid, + info.from_tid, + info.to_pid +@@ -1320,18 +1341,24 @@ impl Thread { + let allow_fds = orig.flags & TF_ACCEPT_FDS != 0; + let reply = Transaction::new_reply(self, process, info, allow_fds)?; + self.inner.lock().push_work(completion); +- orig.from.deliver_reply(Ok(reply), &orig); ++ orig.from.deliver_reply(Ok(reply), &orig, None); + Ok(()) + })() + .map_err(|mut err| { + // At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let + // the sender know that the transaction has completed (with an error in this case). ++ + pr_warn!( +- "Failure {:?} during reply - delivering BR_FAILED_REPLY to sender.", +- err ++ "{}:{} reply to {} failed: {err:?}", ++ info.from_pid, ++ info.from_tid, ++ info.to_pid + ); +- let reply = Err(BR_FAILED_REPLY); +- orig.from.deliver_reply(reply, &orig); ++ ++ let param = err.source.as_ref().map_or(0, |e| e.to_errno()); ++ let ee = ExtendedError::new(info.debug_id as u32, err.reply, param); ++ orig.from ++ .deliver_reply(Err(BR_FAILED_REPLY), &orig, Some(ee)); + err.reply = BR_TRANSACTION_COMPLETE; + err + }); +--- a/drivers/android/binder/transaction.rs ++++ b/drivers/android/binder/transaction.rs +@@ -42,6 +42,7 @@ pub(crate) struct TransactionInfo { + pub(crate) reply: u32, + pub(crate) oneway_spam_suspect: bool, + pub(crate) is_reply: bool, ++ pub(crate) debug_id: usize, + } + + impl TransactionInfo { +@@ -93,7 +94,6 @@ impl Transaction { + from: &Arc, + info: &mut TransactionInfo, + ) -> BinderResult> { +- let debug_id = super::next_debug_id(); + let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0; + let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0; + let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None }; +@@ -101,7 +101,7 @@ impl Transaction { + let mut alloc = match from.copy_transaction_data( + to.clone(), + info, +- debug_id, ++ info.debug_id, + allow_fds, + txn_security_ctx_off.as_mut(), + ) { +@@ -128,7 +128,7 @@ impl Transaction { + let data_address = alloc.ptr; + + Ok(DTRWrap::arc_pin_init(pin_init!(Transaction { +- debug_id, ++ debug_id: info.debug_id, + target_node: Some(target_node), + from_parent, + sender_euid: Kuid::current_euid(), +@@ -152,9 +152,8 @@ impl Transaction { + info: &mut TransactionInfo, + allow_fds: bool, + ) -> BinderResult> { +- let debug_id = super::next_debug_id(); + let mut alloc = +- match from.copy_transaction_data(to.clone(), info, debug_id, allow_fds, None) { ++ match from.copy_transaction_data(to.clone(), info, info.debug_id, allow_fds, None) { + Ok(alloc) => alloc, + Err(err) => { + pr_warn!("Failure in copy_transaction_data: {:?}", err); +@@ -165,7 +164,7 @@ impl Transaction { + alloc.set_info_clear_on_drop(); + } + Ok(DTRWrap::arc_pin_init(pin_init!(Transaction { +- debug_id, ++ debug_id: info.debug_id, + target_node: None, + from_parent: None, + sender_euid: Kuid::current_euid(), +@@ -394,7 +393,7 @@ impl DeliverToRead for Transaction { + let send_failed_reply = ScopeGuard::new(|| { + if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 { + let reply = Err(BR_FAILED_REPLY); +- self.from.deliver_reply(reply, &self); ++ self.from.deliver_reply(reply, &self, None); + } + self.drop_outstanding_txn(); + }); +@@ -478,7 +477,7 @@ impl DeliverToRead for Transaction { + // If this is not a reply or oneway transaction, then send a dead reply. + if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 { + let reply = Err(BR_DEAD_REPLY); +- self.from.deliver_reply(reply, &self); ++ self.from.deliver_reply(reply, &self, None); + } + + self.drop_outstanding_txn(); diff --git a/queue-7.1/rust_binder-reject-context-manager-self-transaction.patch b/queue-7.1/rust_binder-reject-context-manager-self-transaction.patch new file mode 100644 index 0000000000..1b8c62291b --- /dev/null +++ b/queue-7.1/rust_binder-reject-context-manager-self-transaction.patch @@ -0,0 +1,46 @@ +From 6849cabfd30fb5727cfd31e8241e15801e17ebf9 Mon Sep 17 00:00:00 2001 +From: Keshav Verma +Date: Thu, 25 Jun 2026 16:09:57 +0530 +Subject: rust_binder: reject context manager self-transaction + +From: Keshav Verma + +commit 6849cabfd30fb5727cfd31e8241e15801e17ebf9 upstream. + +Rust binder resolved handle 0 to the context manager node, but it does not +reject the case where the caller owns the same node. + +The C binder driver rejects transactions from the context-manager process +to handle 0 after resolving the target node. Match that behavior in Rust +Binder by rejecting handle 0 transactions when the resolved context-manager +node is owned by the calling process. + +This applies to both synchronous and oneway transactions because both paths +resolve the target through Process::get_transaction_node(). + +Cc: stable +Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") +Signed-off-by: Keshav Verma +Reviewed-by: Alice Ryhl +Link: https://patch.msgid.link/20260625103957.730-1-iganschel@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/android/binder/process.rs | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/android/binder/process.rs ++++ b/drivers/android/binder/process.rs +@@ -900,7 +900,11 @@ impl Process { + pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult { + // When handle is zero, try to get the context manager. + if handle == 0 { +- Ok(self.ctx.get_manager_node(true)?) ++ let node_ref = self.ctx.get_manager_node(true)?; ++ if core::ptr::eq(self, &*node_ref.node.owner) { ++ return Err(EINVAL.into()); ++ } ++ Ok(node_ref) + } else { + Ok(self.get_node_from_handle(handle, true)?) + } diff --git a/queue-7.1/rust_binder-synchronize-rust-binder-stats-with-freeze-commands.patch b/queue-7.1/rust_binder-synchronize-rust-binder-stats-with-freeze-commands.patch new file mode 100644 index 0000000000..fa4f0d1905 --- /dev/null +++ b/queue-7.1/rust_binder-synchronize-rust-binder-stats-with-freeze-commands.patch @@ -0,0 +1,70 @@ +From eb1645bf10190e71f6f0316e37ff70755d719b53 Mon Sep 17 00:00:00 2001 +From: Keshav Verma +Date: Tue, 16 Jun 2026 02:47:43 +0530 +Subject: rust_binder: synchronize Rust Binder stats with freeze commands + +From: Keshav Verma + +commit eb1645bf10190e71f6f0316e37ff70755d719b53 upstream. + +Rust Binder stats use BC_COUNT and BR_COUNT to size the command and +return counters, and use event string tables when printing debug +statistics. + +The Binder protocol includes freeze-related commands and return codes, +but the Rust Binder statistics code was not updated to cover them. As a +result, those commands and return codes are not accounted for or printed +by the stats debug output. + +Update the counts and event string tables so these commands and return +codes are included in the debug statistics output. + +Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") +Cc: stable +Acked-by: Carlos Llamas +Reviewed-by: Alice Ryhl +Signed-off-by: Keshav Verma +Link: https://patch.msgid.link/20260615211743.734-1-iganschel@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/android/binder/rust_binder_events.c | 7 ++++++- + drivers/android/binder/stats.rs | 4 ++-- + 2 files changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/android/binder/rust_binder_events.c ++++ b/drivers/android/binder/rust_binder_events.c +@@ -28,6 +28,9 @@ const char * const binder_command_string + "BC_DEAD_BINDER_DONE", + "BC_TRANSACTION_SG", + "BC_REPLY_SG", ++ "BC_REQUEST_FREEZE_NOTIFICATION", ++ "BC_CLEAR_FREEZE_NOTIFICATION", ++ "BC_FREEZE_NOTIFICATION_DONE", + }; + + const char * const binder_return_strings[] = { +@@ -51,7 +54,9 @@ const char * const binder_return_strings + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", + "BR_ONEWAY_SPAM_SUSPECT", +- "BR_TRANSACTION_PENDING_FROZEN" ++ "BR_TRANSACTION_PENDING_FROZEN", ++ "BR_FROZEN_BINDER", ++ "BR_CLEAR_FREEZE_NOTIFICATION_DONE", + }; + + #define CREATE_TRACE_POINTS +--- a/drivers/android/binder/stats.rs ++++ b/drivers/android/binder/stats.rs +@@ -8,8 +8,8 @@ use crate::defs::*; + use kernel::sync::atomic::{ordering::Relaxed, Atomic}; + use kernel::{ioctl::_IOC_NR, seq_file::SeqFile, seq_print}; + +-const BC_COUNT: usize = _IOC_NR(BC_REPLY_SG) as usize + 1; +-const BR_COUNT: usize = _IOC_NR(BR_TRANSACTION_PENDING_FROZEN) as usize + 1; ++const BC_COUNT: usize = _IOC_NR(BC_FREEZE_NOTIFICATION_DONE) as usize + 1; ++const BR_COUNT: usize = _IOC_NR(BR_CLEAR_FREEZE_NOTIFICATION_DONE) as usize + 1; + + pub(crate) static GLOBAL_STATS: BinderStats = BinderStats::new(); + diff --git a/queue-7.1/rust_binder-use-a-u64-stride-when-cleaning-up-the-offsets-array.patch b/queue-7.1/rust_binder-use-a-u64-stride-when-cleaning-up-the-offsets-array.patch new file mode 100644 index 0000000000..5070119dd2 --- /dev/null +++ b/queue-7.1/rust_binder-use-a-u64-stride-when-cleaning-up-the-offsets-array.patch @@ -0,0 +1,62 @@ +From 803c8a9502e9b97cd6ae937618ef4a8fd6274343 Mon Sep 17 00:00:00 2001 +From: Hyunwoo Kim +Date: Sun, 31 May 2026 22:29:24 +0900 +Subject: rust_binder: use a u64 stride when cleaning up the offsets array + +From: Hyunwoo Kim + +commit 803c8a9502e9b97cd6ae937618ef4a8fd6274343 upstream. + +Allocation's Drop walks the offsets array (binder_size_t = u64 entries), +cleaning up the objects, but it used usize instead of u64 for both the +stride and the per-entry read. + +On 64-bit kernels (usize == u64) this is harmless, but on 32-bit kernels +it walks the 8-byte entries in 4-byte steps, iterating an N-entry array +2N times, and reads the always-zero high word as offset 0, cleaning up +the object at offset 0 N extra times. As a result the referenced node or +handle ends up with a lower reference count than it actually has (a +refcount over-decrement), and binder's reference accounting is corrupted; +for example, the owner can be notified of a strong reference release +(BR_RELEASE) even though references still remain. + +Change the stride to u64, and read each entry as a u64, narrowing it to +usize with try_into(). + +On 32-bit ARM, when this over-decrement would drive a count below zero, +the driver's existing refcount guard refuses it and fires: + + rust_binder: Failure: refcount underflow! + +Cc: stable +Fixes: eafedbc7c050 ("rust_binder: add Rust Binder driver") +Signed-off-by: Hyunwoo Kim +Acked-by: Carlos Llamas +Reviewed-by: Alice Ryhl +Link: https://patch.msgid.link/ahw3tFhLz9bMMJAO@v4bel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/android/binder/allocation.rs | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/android/binder/allocation.rs ++++ b/drivers/android/binder/allocation.rs +@@ -259,7 +259,7 @@ impl Drop for Allocation { + + if let Some(offsets) = info.offsets.clone() { + let view = AllocationView::new(self, offsets.start); +- for i in offsets.step_by(size_of::()) { ++ for i in offsets.step_by(size_of::()) { + if view.cleanup_object(i).is_err() { + pr_warn!("Error cleaning up object at offset {}\n", i) + } +@@ -420,7 +420,8 @@ impl<'a> AllocationView<'a> { + } + + fn cleanup_object(&self, index_offset: usize) -> Result { +- let offset = self.alloc.read(index_offset)?; ++ let offset = self.alloc.read::(index_offset)?; ++ let offset: usize = offset.try_into().map_err(|_| EINVAL)?; + let header = self.read::(offset)?; + match header.type_ { + BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => { diff --git a/queue-7.1/series b/queue-7.1/series index 2ec43d2bcf..de58a9f5a3 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -116,3 +116,11 @@ bluetooth-btusb-fix-use-after-free-on-marvell-probe-failure.patch bluetooth-btusb-fix-wakeup-source-leak-on-probe-failure.patch binder-fix-uaf-in-binder_thread_release.patch binder-fix-uaf-in-binder_free_transaction.patch +rust_binder-use-a-u64-stride-when-cleaning-up-the-offsets-array.patch +rust_binder-fix-binder_get_extended_error.patch +rust_binder-reject-context-manager-self-transaction.patch +rust_binder-synchronize-rust-binder-stats-with-freeze-commands.patch +rust_binder-clear-freeze-listener-on-node-removal.patch +usb-xhci-fix-sleep-in-atomic-context-in-xhci_free_streams.patch +xhci-sideband-fix-ring-sg-table-pages-leak.patch +usb-typec-tcpci_rt1711h-unregister-tcpci-port-with-devres.patch diff --git a/queue-7.1/usb-typec-tcpci_rt1711h-unregister-tcpci-port-with-devres.patch b/queue-7.1/usb-typec-tcpci_rt1711h-unregister-tcpci-port-with-devres.patch new file mode 100644 index 0000000000..dceb783e95 --- /dev/null +++ b/queue-7.1/usb-typec-tcpci_rt1711h-unregister-tcpci-port-with-devres.patch @@ -0,0 +1,77 @@ +From e8da46d99d3710106e7c44db14566bf9b57386b5 Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Mon, 6 Jul 2026 23:53:12 +0900 +Subject: usb: typec: tcpci_rt1711h: unregister TCPCI port with devres + +From: Myeonghun Pak + +commit e8da46d99d3710106e7c44db14566bf9b57386b5 upstream. + +rt1711h_probe() registers the TCPCI port before requesting the interrupt +and enabling alert interrupts. If either of those later steps fails, the +probe function returns without unregistering the TCPCI port. The explicit +unregister currently only happens from the remove callback. + +Register a devres action immediately after tcpci_register_port() succeeds, +so tcpci_unregister_port() runs on later probe failures and on driver +detach. Drop the remove callback to avoid unregistering the same port +twice. + +This issue was identified during our ongoing static-analysis research while +reviewing kernel code. + +Fixes: 302c570bf36e ("usb: typec: tcpci_rt1711h: avoid screaming irq causing boot hangs") +Cc: stable +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260706145312.37260-1-mhun512@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/tcpm/tcpci_rt1711h.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c ++++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c +@@ -295,6 +295,8 @@ static int rt1711h_sw_reset(struct rt171 + return 0; + } + ++static void rt1711h_unregister_tcpci_port(void *tcpci); ++ + static int rt1711h_probe(struct i2c_client *client) + { + int ret; +@@ -340,6 +342,10 @@ static int rt1711h_probe(struct i2c_clie + if (IS_ERR_OR_NULL(chip->tcpci)) + return PTR_ERR(chip->tcpci); + ++ ret = devm_add_action_or_reset(chip->dev, rt1711h_unregister_tcpci_port, chip->tcpci); ++ if (ret) ++ return ret; ++ + ret = devm_request_threaded_irq(chip->dev, client->irq, NULL, + rt1711h_irq, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, +@@ -357,11 +363,9 @@ static int rt1711h_probe(struct i2c_clie + return 0; + } + +-static void rt1711h_remove(struct i2c_client *client) ++static void rt1711h_unregister_tcpci_port(void *tcpci) + { +- struct rt1711h_chip *chip = i2c_get_clientdata(client); +- +- tcpci_unregister_port(chip->tcpci); ++ tcpci_unregister_port(tcpci); + } + + static const struct rt1711h_chip_info rt1711h = { +@@ -394,7 +398,6 @@ static struct i2c_driver rt1711h_i2c_dri + .of_match_table = rt1711h_of_match, + }, + .probe = rt1711h_probe, +- .remove = rt1711h_remove, + .id_table = rt1711h_id, + }; + module_i2c_driver(rt1711h_i2c_driver); diff --git a/queue-7.1/usb-xhci-fix-sleep-in-atomic-context-in-xhci_free_streams.patch b/queue-7.1/usb-xhci-fix-sleep-in-atomic-context-in-xhci_free_streams.patch new file mode 100644 index 0000000000..1571b2272c --- /dev/null +++ b/queue-7.1/usb-xhci-fix-sleep-in-atomic-context-in-xhci_free_streams.patch @@ -0,0 +1,86 @@ +From 42c37c4b75d38b51d84f31a8e29427f5e06a7c2a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E8=83=A1=E8=BF=9E=E5=8B=A4?= +Date: Fri, 3 Jul 2026 17:40:33 +0300 +Subject: usb: xhci: Fix sleep in atomic context in xhci_free_streams() + +From: 胡连勤 + +commit 42c37c4b75d38b51d84f31a8e29427f5e06a7c2a upstream. + +When a USB device with active stream endpoints is disconnected, +xhci_free_streams() is called from the hub_event workqueue to +free the stream resources. It calls xhci_free_stream_info() +while holding xhci->lock with irqs disabled. + +xhci_free_stream_info() invokes xhci_free_stream_ctx(), which +calls dma_free_coherent() for large stream context arrays. + +dma_free_coherent() can sleep (e.g. via vunmap), triggering +a BUG when called from atomic context. + +Call trace: + dma_free_attrs+0x174/0x220 + xhci_free_stream_info+0xd0/0x11c + xhci_free_streams+0x278/0x37c + usb_free_streams+0x98/0xc0 + usb_unbind_interface+0x1b8/0x2f8 + device_release_driver_internal+0x1d4/0x2cc + device_release_driver+0x18/0x28 + bus_remove_device+0x160/0x1a4 + device_del+0x1ec/0x350 + usb_disable_device+0x98/0x214 + usb_disconnect+0xf0/0x35c + hub_event+0xab4/0x19ec + process_one_work+0x278/0x63c + +Fix this by saving the stream_info pointers and clearing the +ep references under the lock, then calling xhci_free_stream_info() +outside the lock where sleeping is allowed. + +Fixes: 8df75f42f8e6 ("USB: xhci: Add memory allocation for USB3 bulk streams.") +Cc: stable +Signed-off-by: Lianqin Hu +Signed-off-by: Mathias Nyman +Link: https://patch.msgid.link/20260703144033.483286-3-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -3788,6 +3788,7 @@ static int xhci_free_streams(struct usb_ + struct xhci_virt_device *vdev; + struct xhci_command *command; + struct xhci_input_control_ctx *ctrl_ctx; ++ struct xhci_stream_info *stream_info[EP_CTX_PER_DEV]; + unsigned int ep_index; + unsigned long flags; + u32 changed_ep_bitmask; +@@ -3848,10 +3849,15 @@ static int xhci_free_streams(struct usb_ + if (ret < 0) + return ret; + ++ /* ++ * dma_free_coherent() called by xhci_free_stream_info() may sleep, ++ * so save stream_info pointers and clear references under lock, ++ * then free the memory outside lock. ++ */ + spin_lock_irqsave(&xhci->lock, flags); + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); +- xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); ++ stream_info[i] = vdev->eps[ep_index].stream_info; + vdev->eps[ep_index].stream_info = NULL; + /* FIXME Unset maxPstreams in endpoint context and + * update deq ptr to point to normal string ring. +@@ -3861,6 +3867,9 @@ static int xhci_free_streams(struct usb_ + } + spin_unlock_irqrestore(&xhci->lock, flags); + ++ for (i = 0; i < num_eps; i++) ++ xhci_free_stream_info(xhci, stream_info[i]); ++ + return 0; + } + diff --git a/queue-7.1/xhci-sideband-fix-ring-sg-table-pages-leak.patch b/queue-7.1/xhci-sideband-fix-ring-sg-table-pages-leak.patch new file mode 100644 index 0000000000..5cc56d3dc5 --- /dev/null +++ b/queue-7.1/xhci-sideband-fix-ring-sg-table-pages-leak.patch @@ -0,0 +1,43 @@ +From 49f6e3c3ef19f04f6657ed8dce550e36c763abb8 Mon Sep 17 00:00:00 2001 +From: Xu Rao +Date: Fri, 3 Jul 2026 17:40:32 +0300 +Subject: xhci: sideband: fix ring sg table pages leak + +From: Xu Rao + +commit 49f6e3c3ef19f04f6657ed8dce550e36c763abb8 upstream. + +xhci_ring_to_sgtable() allocates a temporary pages array and +uses it to build the returned sg_table with +sg_alloc_table_from_pages(). + +The error paths free the pages array, but the success path +returns the sg_table without freeing it. This leaks the temporary +array every time a sideband client gets an endpoint or event ring +buffer. + +Free the pages array after sg_alloc_table_from_pages() succeeds. +The returned sg_table has its own scatterlist entries and does not +depend on the temporary array after construction. + +Fixes: de66754e9f80 ("xhci: sideband: add initial api to register a secondary interrupter entity") +Cc: stable +Signed-off-by: Xu Rao +Signed-off-by: Mathias Nyman +Link: https://patch.msgid.link/20260703144033.483286-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-sideband.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/host/xhci-sideband.c ++++ b/drivers/usb/host/xhci-sideband.c +@@ -58,6 +58,8 @@ xhci_ring_to_sgtable(struct xhci_sideban + if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) + goto err; + ++ kvfree(pages); ++ + /* + * Save first segment dma address to sg dma_address field for the sideband + * client to have access to the IOVA of the ring.