Thread (5 messages) flat view 5 messages, 3 authors, 11d ago

Re: [PATCH v2 net] sctp: avoid livelock while updating retransmit path

From: Xin Long <lucien.xin@gmail.com>
Date: 2026-09-11 00:25:47
Also in: linux-sctp, lkml, stable

On Tue, Sep 1, 2026 at 10:53 PM Yiqi Sun [off-list ref] wrote:
quoted hunk ↗ jump to hunk
On Thu, Aug 27, 2026 at 3:50 AM, Xin Long wrote:
quoted
After removing the continue, I think you can keep using
if (trans == asoc->peer.retran_path) here without 'last' needed.
Yes. The v1 'last' variable was redundant once the SCTP_UNCONFIRMED
path no longer uses continue. Drop it in this revision and retain the
original wraparound comparison after the candidate-selection block.

The reproducer is attached.

sctp_assoc_update_retran_path() walks the association transport list
from the current retransmit path's successor and stops once it reaches
the current retransmit path again. However, the loop skips transports in
SCTP_UNCONFIRMED state before checking for the wraparound condition.

This makes the loop non-terminating when the association contains only
UNCONFIRMED transports at that point and asoc->peer.retran_path is also
UNCONFIRMED. One way to reach that state is through ASCONF wildcard
DEL-IP processing after an unconfirmed address is selected as the
primary transport. sctp_assoc_del_nonprimary_peers() then removes the
other transports one by one; when removing the current retran_path,
sctp_assoc_rm_peer() calls sctp_assoc_update_retran_path() before
unlinking it. If the remaining candidate and the current retran_path are
both UNCONFIRMED, the loop repeatedly continues before it can observe
that it has completed a full pass.

Fix this by considering a transport only when it is not UNCONFIRMED,
then checking whether the walk has returned to retran_path. This makes
the full-pass termination independent of the transport state while
preserving the existing fallback selection semantics.

Also restore the NULL guard around the retran_path assignment. In the
all-UNCONFIRMED case there is no eligible replacement transport, and
installing NULL would leave later retransmit-path users and the debug
print with a NULL path.

Fixes: 4c47af4d5eb2 ("net: sctp: rework multihoming retransmission path selection to rfc4960")
Signed-off-by: Yiqi Sun <redacted>
---
Changes in v2:
- Drop the redundant 'last' variable as suggested by Xin Long.
- Link to v1: https://lore.kernel.org/r/20260827075006.3979566-1-sunyiqixm@gmail.com/ (local)
---
 net/sctp/associola.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index c0512c827d0f..4521be3bd85a 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1289,18 +1289,19 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
                /* Manually skip the head element. */
                if (&trans->transports == &asoc->peer.transport_addr_list)
                        continue;
-               if (trans->state == SCTP_UNCONFIRMED)
-                       continue;
-               trans_next = sctp_trans_elect_best(trans, trans_next);
-               /* Active is good enough for immediate return. */
-               if (trans_next->state == SCTP_ACTIVE)
-                       break;
+               if (trans->state != SCTP_UNCONFIRMED) {
+                       trans_next = sctp_trans_elect_best(trans, trans_next);
+                       /* Active is good enough for immediate return. */
+                       if (trans_next->state == SCTP_ACTIVE)
+                               break;
+               }
                /* We've reached the end, time to update path. */
                if (trans == asoc->peer.retran_path)
                        break;
        }

-       asoc->peer.retran_path = trans_next;
+       if (trans_next)
+               asoc->peer.retran_path = trans_next;

        pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
                 __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
--
2.34.1
Hi Yiqi,

Could you repost the patch in a separate thread without including
the discussion below in the commit message?


    On Thu, Aug 27, 2026 at 3:50 AM, Xin Long wrote:
    > After removing the continue, I think you can keep using
    > if (trans == asoc->peer.retran_path) here without 'last' needed.

    Yes. The v1 'last' variable was redundant once the SCTP_UNCONFIRMED
    path no longer uses continue. Drop it in this revision and retain the
    original wraparound comparison after the candidate-selection block.

Thanks.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help