[PATCH v2 2/2] platform/surface: aggregator: Fix use-after-free in ssh_ptl_shutdown()
From: Wentao Liang
Date: Sat Nov 07 2026 - 03:10:08 EST
Both loops that drain the local packet lists in ssh_ptl_shutdown() call
ssh_packet_put() on the loop variable. This drops the reference that the
queue or the pending set held on the packet, which can be the last one,
so the packet may be freed before the iterator advances to the next
entry. The iterator then reads the list node of the freed packet to do
so.
Use list_for_each_entry_safe() for both loops, which caches the next
entry while the current packet is still alive.
Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem")
Cc: stable@xxxxxxxxxxxxxxx
Acked-by: Maximilian Luz <luzmaximilian@xxxxxxxxx>
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
drivers/platform/surface/aggregator/ssh_packet_layer.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
index a51395942747..871780828419 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
@@ -1989,7 +1989,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl)
spin_unlock(&ptl->pending.lock);
/* Complete and drop packets on complete_q. */
- list_for_each_entry(p, &complete_q, queue_node) {
+ list_for_each_entry_safe(p, n, &complete_q, queue_node) {
if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
__ssh_ptl_complete(p, -ESHUTDOWN);
@@ -1997,7 +1997,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl)
}
/* Complete and drop packets on complete_p. */
- list_for_each_entry(p, &complete_p, pending_node) {
+ list_for_each_entry_safe(p, n, &complete_p, pending_node) {
if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
__ssh_ptl_complete(p, -ESHUTDOWN);
--
2.34.1