* [PATCH net v3 0/2] sctp: re-point retained control chunks on association migration @ 2026-09-26 10:03 Jun Yang 2026-09-26 10:03 ` [PATCH net v3 1/2] sctp: hold shkey across socket migration Jun Yang 2026-09-26 10:03 ` [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration Jun Yang 0 siblings, 2 replies; 7+ messages in thread From: Jun Yang @ 2026-09-26 10:03 UTC (permalink / raw) To: Marcelo Ricardo Leitner, Xin Long Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-sctp, netdev, David Lee, Kyle Zeng Patch 1 includes David Lee's shared-key fix [1] without code changes, so the control-chunk fix in patch 2 can be applied with its prerequisite. Since v2 [2], patch 2 calls cb() directly for control chunks, as Xin suggested, and keeps the existing DATA checks. [1] https://lore.kernel.org/netdev/20260731120558.558957-1-david.lee@trailofbits.com/ [2] https://lore.kernel.org/netdev/20260804113705.45754-1-juny24602@gmail.com/ David Lee (1): sctp: hold shkey across socket migration Jun Yang (1): sctp: re-point retained control chunks on association migration include/net/sctp/sm.h | 1 + net/sctp/sm_make_chunk.c | 2 +- net/sctp/socket.c | 41 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 38 insertions(+), 6 deletions(-) base-commit: a644f09b2090ad22a13fbcf9d141084f573108ef ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net v3 1/2] sctp: hold shkey across socket migration 2026-09-26 10:03 [PATCH net v3 0/2] sctp: re-point retained control chunks on association migration Jun Yang @ 2026-09-26 10:03 ` Jun Yang 2026-09-30 0:06 ` netdev-bot+sashiko 2026-09-26 10:03 ` [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration Jun Yang 1 sibling, 1 reply; 7+ messages in thread From: Jun Yang @ 2026-09-26 10:03 UTC (permalink / raw) To: Marcelo Ricardo Leitner, Xin Long Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-sctp, netdev, David Lee, Kyle Zeng From: David Lee <david.lee@trailofbits.com> sctp_sock_migrate() transfers queued DATA skbs from the old socket to the new one. skb_orphan() invokes sctp_wfree() during that transfer and drops the skb-owned shared-key reference. If userspace has removed that key from the association, this can be the final reference. The following sctp_set_owner_w() then dereferences the freed chunk->shkey while trying to take the new owner reference. Take a temporary shared-key reference before orphaning the skb and release it after the new owner has taken its reference. This preserves the selected authentication key throughout the ownership transfer. Bug found and triaged by OpenAI Security Research and validated by Trail of Bits. Fixes: 1b1e0bc99474 ("sctp: add refcnt support for sh_key") Assisted-by: Codex:gpt-5.6-sol gpt-5.5-cyber Signed-off-by: Kyle Zeng <kylebot@openai.com> Acked-by: Xin Long <lucien.xin@gmail.com> --- Original submission: https://lore.kernel.org/netdev/20260731120558.558957-1-david.lee@trailofbits.com/ net/sctp/socket.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c7b9e325ec1c..4a08023d52aa 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -147,9 +147,19 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) static void sctp_clear_owner_w(struct sctp_chunk *chunk) { + /* Keep the shkey alive until the new owner takes its reference. */ + if (chunk->shkey) + sctp_auth_shkey_hold(chunk->shkey); skb_orphan(chunk->skb); } +static void sctp_set_owner_w_migrate(struct sctp_chunk *chunk) +{ + sctp_set_owner_w(chunk); + if (chunk->shkey) + sctp_auth_shkey_release(chunk->shkey); +} + #define traverse_and_process() \ do { \ msg = chunk->msg; \ @@ -9632,7 +9642,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w); sctp_assoc_migrate(assoc, newsk); - sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w); + sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w_migrate); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag. ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 1/2] sctp: hold shkey across socket migration 2026-09-26 10:03 ` [PATCH net v3 1/2] sctp: hold shkey across socket migration Jun Yang @ 2026-09-30 0:06 ` netdev-bot+sashiko 2026-10-01 1:38 ` Xin Long 0 siblings, 1 reply; 7+ messages in thread From: netdev-bot+sashiko @ 2026-09-30 0:06 UTC (permalink / raw) To: juny24602 Cc: marcelo.leitner, lucien.xin, davem, edumazet, kuba, pabeni, horms, linux-sctp, netdev, david.lee, kylebot, junvyyang, stable, corvus Thank you for your contribution! Sashiko AI review found more severe issue(s) in other patches of this series. This mail is only an FYI, in case you want to address the nit picks below when you respin. Low priority / nit picks for your consideration: - [Low] The commit author, David Lee <david.lee@trailofbits.com>, has no Signed-off-by line. -- sctp: hold shkey across socket migration sctp_sock_migrate() orphans queued tx chunks before moving the association to the new socket. skb_orphan() calls sctp_wfree(), which can drop the last reference on chunk->shkey before sctp_set_owner_w() uses it again. This patch takes a temporary shkey reference in sctp_clear_owner_w() and drops it in a new sctp_set_owner_w_migrate() helper, after the new owner has taken its own reference. > Fixes: 1b1e0bc99474 ("sctp: add refcnt support for sh_key") > Assisted-by: Codex:gpt-5.6-sol gpt-5.5-cyber > Signed-off-by: Kyle Zeng <kylebot@openai.com> > Acked-by: Xin Long <lucien.xin@gmail.com> [Severity: Low] This isn't a bug, but is there a Signed-off-by missing for the patch author? The Author: line is David Lee <david.lee@trailofbits.com>. The only Signed-off-by is from Kyle Zeng <kylebot@openai.com>, and there is no Co-developed-by tag. The original submission for this patch seems to have come from david.lee@trailofbits.com. That means the submitter has not signed off either. Documentation/process/submitting-patches.rst requires a DCO sign-off from the author. checkpatch.pl reports this case as "Missing Signed-off-by: line by nominal patch author". Which of these is the intended attribution? - Kyle Zeng is the author. The patch would then need a From: Kyle Zeng line and a sign-off from the submitter. - David Lee is the author. He would then need to add his own Signed-off-by, plus a Co-developed-by for Kyle Zeng if he co-wrote the patch. The next patch in the series, "sctp: re-point retained control chunks on association migration", has the same trailers. -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260926100359.78731-1-juny24602%40gmail.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 1/2] sctp: hold shkey across socket migration 2026-09-30 0:06 ` netdev-bot+sashiko @ 2026-10-01 1:38 ` Xin Long 0 siblings, 0 replies; 7+ messages in thread From: Xin Long @ 2026-10-01 1:38 UTC (permalink / raw) To: netdev-bot+sashiko Cc: juny24602, marcelo.leitner, davem, edumazet, kuba, pabeni, horms, linux-sctp, netdev, david.lee, kylebot, junvyyang, stable, corvus On Tue, Sep 29, 2026 at 8:06 PM <netdev-bot+sashiko@kernel.org> wrote: > > Thank you for your contribution! Sashiko AI review found more severe > issue(s) in other patches of this series. This mail is only an FYI, in case > you want to address the nit picks below when you respin. > > Low priority / nit picks for your consideration: > > - [Low] The commit author, David Lee <david.lee@trailofbits.com>, has no > Signed-off-by line. > > -- > > sctp: hold shkey across socket migration > > sctp_sock_migrate() orphans queued tx chunks before moving the association > to the new socket. skb_orphan() calls sctp_wfree(), which can drop the last > reference on chunk->shkey before sctp_set_owner_w() uses it again. This > patch takes a temporary shkey reference in sctp_clear_owner_w() and drops > it in a new sctp_set_owner_w_migrate() helper, after the new owner has > taken its own reference. > > > Fixes: 1b1e0bc99474 ("sctp: add refcnt support for sh_key") > > Assisted-by: Codex:gpt-5.6-sol gpt-5.5-cyber > > Signed-off-by: Kyle Zeng <kylebot@openai.com> > > Acked-by: Xin Long <lucien.xin@gmail.com> > > [Severity: Low] > This isn't a bug, but is there a Signed-off-by missing for the patch > author? > > The Author: line is David Lee <david.lee@trailofbits.com>. The only > Signed-off-by is from Kyle Zeng <kylebot@openai.com>, and there is no > Co-developed-by tag. > > The original submission for this patch seems to have come from > david.lee@trailofbits.com. That means the submitter has not signed off > either. > > Documentation/process/submitting-patches.rst requires a DCO sign-off > from the author. checkpatch.pl reports this case as "Missing > Signed-off-by: line by nominal patch author". > > Which of these is the intended attribution? > > - Kyle Zeng is the author. The patch would then need a From: Kyle Zeng > line and a sign-off from the submitter. > > - David Lee is the author. He would then need to add his own > Signed-off-by, plus a Co-developed-by for Kyle Zeng if he co-wrote > the patch. > > The next patch in the series, "sctp: re-point retained control chunks > on association migration", has the same trailers. > Please add Signed-off-by for the author as well: Signed-off-by: David Lee <david.lee@trailofbits.com> Thanks. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration 2026-09-26 10:03 [PATCH net v3 0/2] sctp: re-point retained control chunks on association migration Jun Yang 2026-09-26 10:03 ` [PATCH net v3 1/2] sctp: hold shkey across socket migration Jun Yang @ 2026-09-26 10:03 ` Jun Yang 2026-09-30 0:06 ` netdev-bot+sashiko 1 sibling, 1 reply; 7+ messages in thread From: Jun Yang @ 2026-09-26 10:03 UTC (permalink / raw) To: Marcelo Ricardo Leitner, Xin Long Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-sctp, netdev, David Lee, Kyle Zeng, Jun Yang, stable, TencentOS Corvus AI From: Jun Yang <junvyyang@tencent.com> sctp_sock_migrate() transfers DATA chunk ownership but leaves retained control chunks pointing at the old socket. A later retransmission can therefore access the socket after it has been freed. Extend the migration walk to cover retained control chunks and use sctp_control_set_owner_w() to assign their new owner. Save the old chunk->shkey before setting the new owner and release that key afterward, since sctp_control_set_owner_w() may select a different asoc->shkey. Fixes: d04adf1b3551 ("sctp: reset owner sk for data chunks on out queues when migrating a sock") Cc: stable@kernel.org Reported-by: TencentOS Corvus AI <corvus@tencent.com> Assisted-by: tencentos-corvus-ai:hy4-preview Signed-off-by: Jun Yang <junvyyang@tencent.com> --- A KASAN reproducer for this issue is available if requested. v3: - Call cb() directly for control chunks. - Include the shared-key prerequisite as patch 1/2. v2: https://lore.kernel.org/netdev/20260804113705.45754-1-juny24602@gmail.com/ v1: https://lore.kernel.org/netdev/20260730090537.27629-1-juny24602@gmail.com/ include/net/sctp/sm.h | 1 + net/sctp/sm_make_chunk.c | 2 +- net/sctp/socket.c | 37 +++++++++++++++++++++++++++++-------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 3bfd261a53cc..76605d1ee839 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -252,6 +252,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, struct sctp_fwdtsn_skip *skiplist); struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc, __u16 key_id); +void sctp_control_set_owner_w(struct sctp_chunk *chunk); struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc, __u16 stream_num, __be16 *stream_list, bool out, bool in); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 84a4c97d0f75..b2eb7568a58e 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -94,7 +94,7 @@ static void sctp_control_release_owner(struct sk_buff *skb) } } -static void sctp_control_set_owner_w(struct sctp_chunk *chunk) +void sctp_control_set_owner_w(struct sctp_chunk *chunk) { struct sctp_association *asoc = chunk->asoc; struct sk_buff *skb = chunk->skb; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 4a08023d52aa..efee9e3e671e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -155,9 +155,15 @@ static void sctp_clear_owner_w(struct sctp_chunk *chunk) static void sctp_set_owner_w_migrate(struct sctp_chunk *chunk) { - sctp_set_owner_w(chunk); - if (chunk->shkey) - sctp_auth_shkey_release(chunk->shkey); + struct sctp_shared_key *shkey = chunk->shkey; + + if (chunk->msg) + sctp_set_owner_w(chunk); + else + sctp_control_set_owner_w(chunk); + + if (shkey) + sctp_auth_shkey_release(shkey); } #define traverse_and_process() \ @@ -173,9 +179,9 @@ do { \ prev_msg = msg; \ } while (0) -static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, - bool clear, - void (*cb)(struct sctp_chunk *)) +static void sctp_for_each_tx_chunk(struct sctp_association *asoc, + bool clear, + void (*cb)(struct sctp_chunk *)) { struct sctp_datamsg *msg, *prev_msg = NULL; @@ -198,6 +204,21 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, list_for_each_entry(chunk, &q->out_chunk_list, list) traverse_and_process(); + + list_for_each_entry(chunk, &q->control_chunk_list, list) + cb(chunk); + + list_for_each_entry(chunk, &asoc->asconf_ack_list, transmitted_list) + cb(chunk); + + list_for_each_entry(chunk, &asoc->addip_chunk_list, list) + cb(chunk); + + if (asoc->strreset_chunk) + cb(asoc->strreset_chunk); + + if (asoc->addip_last_asconf) + cb(asoc->addip_last_asconf); } static void sctp_for_each_rx_skb(struct sctp_association *asoc, struct sock *sk, @@ -9640,9 +9661,9 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, * paths won't try to lock it and then oldsk. */ lock_sock_nested(newsk, SINGLE_DEPTH_NESTING); - sctp_for_each_tx_datachunk(assoc, true, sctp_clear_owner_w); + sctp_for_each_tx_chunk(assoc, true, sctp_clear_owner_w); sctp_assoc_migrate(assoc, newsk); - sctp_for_each_tx_datachunk(assoc, false, sctp_set_owner_w_migrate); + sctp_for_each_tx_chunk(assoc, false, sctp_set_owner_w_migrate); /* If the association on the newsk is already closed before accept() * is called, set RCV_SHUTDOWN flag. ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration 2026-09-26 10:03 ` [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration Jun Yang @ 2026-09-30 0:06 ` netdev-bot+sashiko 2026-10-01 1:58 ` Xin Long 0 siblings, 1 reply; 7+ messages in thread From: netdev-bot+sashiko @ 2026-09-30 0:06 UTC (permalink / raw) To: juny24602 Cc: marcelo.leitner, lucien.xin, davem, edumazet, kuba, pabeni, horms, linux-sctp, netdev, david.lee, kylebot, junvyyang, stable, corvus Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider. Critical: 0 · High: 1 · Medium: 1 · Low: 0 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [High] In net/sctp/socket.c, sctp_for_each_tx_chunk() walks the control chunks with a bare cb(chunk) on q->control_chunk_list,… - [Medium] sctp_set_owner_w_migrate() passes control chunks to sctp_control_set_owner_w(). -- sctp: re-point retained control chunks on association migration This patch extends the tx walk in sctp_sock_migrate() to cover retained control chunks as well: control_chunk_list, asconf_ack_list, addip_chunk_list, strreset_chunk and addip_last_asconf. Their owner is moved to the new socket. It exports sctp_control_set_owner_w() for chunks that have no datamsg, and saves the old chunk->shkey so that key can be released after the new owner is set. > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > index 4a08023d52aae..efee9e3e671ef 100644 > --- a/net/sctp/socket.c > +++ b/net/sctp/socket.c > @@ -155,9 +155,15 @@ static void sctp_clear_owner_w(struct sctp_chunk *chunk) > > static void sctp_set_owner_w_migrate(struct sctp_chunk *chunk) > { > - sctp_set_owner_w(chunk); > - if (chunk->shkey) > - sctp_auth_shkey_release(chunk->shkey); > + struct sctp_shared_key *shkey = chunk->shkey; > + > + if (chunk->msg) > + sctp_set_owner_w(chunk); > + else > + sctp_control_set_owner_w(chunk); > + > + if (shkey) > + sctp_auth_shkey_release(shkey); > } [Severity: Medium] For control chunks with chunk->auth set, sctp_control_set_owner_w() always does this: if (chunk->auth) { chunk->shkey = asoc->shkey; sctp_auth_shkey_hold(chunk->shkey); } After peeloff/accept, a retained control chunk (an ASCONF-ACK, addip_last_asconf or strreset_chunk) that was built under key K is switched to whatever key is active at migration time. Is that intended? The DATA path through sctp_set_owner_w() keeps the key that was already selected. The prerequisite shkey patch also describes the transfer as keeping the selected authentication key. The commit message says: "since sctp_control_set_owner_w() may select a different asoc->shkey." It doesn't mention that retransmissions of these chunks would then be authenticated with a different key id. Can this also lose the SCTP_AUTH_FREE_KEY event for K? Suppose K was deactivated while chunk C still holds it, so K's refcnt is 2. K cannot be the active key at that point, per sctp_auth_deact_key_id(): clear pass: sctp_clear_owner_w() sctp_auth_shkey_hold(K) K refcnt 3 skb_orphan() sctp_control_release_owner() sees refcnt 3, no event sctp_auth_shkey_release(K) K refcnt 2 set pass: sctp_set_owner_w_migrate() sctp_control_set_owner_w() C->shkey = K', hold K' sctp_auth_shkey_release(K) K refcnt 1 The last chunk reference on K is dropped by the plain sctp_auth_shkey_release() in sctp_set_owner_w_migrate(). That call skips the refcnt == 2 check, so no later code path sends SCTP_AUTH_FREE_KEY for K. [ ... ] > @@ -198,6 +204,21 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, > > list_for_each_entry(chunk, &q->out_chunk_list, list) > traverse_and_process(); > + > + list_for_each_entry(chunk, &q->control_chunk_list, list) > + cb(chunk); > + > + list_for_each_entry(chunk, &asoc->asconf_ack_list, transmitted_list) > + cb(chunk); > + > + list_for_each_entry(chunk, &asoc->addip_chunk_list, list) > + cb(chunk); > + > + if (asoc->strreset_chunk) > + cb(asoc->strreset_chunk); > + > + if (asoc->addip_last_asconf) > + cb(asoc->addip_last_asconf); > } [Severity: High] These new walks call cb() without any filter. The DATA walks go through traverse_and_process(), which checks c->skb->sk against asoc->base.sk so each chunk is processed only once. Can a retained control chunk be reachable from more than one of these lists or pointers at once? sctp_process_asconf() links the ASCONF-ACK on asconf_ack_list through transmitted_list: sctp_chunk_hold(asconf_ack); list_add_tail(&asconf_ack->transmitted_list, &asoc->asconf_ack_list); sctp_sf_do_asconf() then queues the same chunk on control_chunk_list through ->list with SCTP_CMD_REPLY. sctp_assoc_lookup_asconf_ack() already skips entries where sctp_chunk_pending() is true, so being on both lists is an expected state. strreset_chunk and addip_last_asconf are also queued on control_chunk_list while the pointer is still held. These chunks can stay on control_chunk_list across a flush. sctp_outq_flush_ctrl() skips them while src_out_of_asoc_ok is set, which userspace can trigger through sctp_send_asconf_del_ip(): if (ctx->asoc->src_out_of_asoc_ok && chunk->chunk_hdr->type != SCTP_CID_ASCONF) continue; It also puts back chunks that fail to transmit: if (status != SCTP_XMIT_OK) { /* put the chunk back */ list_add(&chunk->list, &ctx->q->control_chunk_list); Take such a chunk with chunk->auth set, old key K and new key K'. The refcounts go like this: clear pass, first visit: sctp_clear_owner_w() hold K skb_orphan() destructor releases K, clears destructor clear pass, second visit: sctp_clear_owner_w() hold K skb_orphan() no destructor, nothing released set pass, first visit: sctp_set_owner_w_migrate() hold K', release K set pass, second visit: sctp_set_owner_w_migrate() hold K', release K' (chunk->shkey is K') Does this leak a reference on K? The net change is +1 on K. The struct sctp_shared_key and its sctp_auth_bytes would then never be freed, and the refcnt == 2 check in sctp_control_release_owner() could never fire for K. A local user who controls both ends over loopback could repeat this for each association. Could these walks skip chunks that were already handled, for example with the same skb->sk check that traverse_and_process() uses? -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260926100359.78731-1-juny24602%40gmail.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration 2026-09-30 0:06 ` netdev-bot+sashiko @ 2026-10-01 1:58 ` Xin Long 0 siblings, 0 replies; 7+ messages in thread From: Xin Long @ 2026-10-01 1:58 UTC (permalink / raw) To: netdev-bot+sashiko Cc: juny24602, marcelo.leitner, davem, edumazet, kuba, pabeni, horms, linux-sctp, netdev, david.lee, kylebot, junvyyang, stable, corvus On Tue, Sep 29, 2026 at 8:06 PM <netdev-bot+sashiko@kernel.org> wrote: > > Thank you for your contribution! Sashiko AI review found 2 potential > issue(s) to consider. > > Critical: 0 · High: 1 · Medium: 1 · Low: 0 > > If you believe none of the issues are legitimate, please reply to each > issue of Medium severity or higher and explain why the AI is wrong. > If any of them are legitimate and you plan to respin, please let patchwork > know by including "pw-bot: cr" as a separate line at the end of your reply > (one such reply per series is enough). > > - [High] In net/sctp/socket.c, sctp_for_each_tx_chunk() walks the control > chunks with a bare cb(chunk) on q->control_chunk_list,… > - [Medium] sctp_set_owner_w_migrate() passes control chunks to > sctp_control_set_owner_w(). > > -- > > sctp: re-point retained control chunks on association migration > > This patch extends the tx walk in sctp_sock_migrate() to cover retained > control chunks as well: control_chunk_list, asconf_ack_list, > addip_chunk_list, strreset_chunk and addip_last_asconf. Their owner is > moved to the new socket. It exports sctp_control_set_owner_w() for chunks > that have no datamsg, and saves the old chunk->shkey so that key can be > released after the new owner is set. > > > diff --git a/net/sctp/socket.c b/net/sctp/socket.c > > index 4a08023d52aae..efee9e3e671ef 100644 > > --- a/net/sctp/socket.c > > +++ b/net/sctp/socket.c > > @@ -155,9 +155,15 @@ static void sctp_clear_owner_w(struct sctp_chunk *chunk) > > > > static void sctp_set_owner_w_migrate(struct sctp_chunk *chunk) > > { > > - sctp_set_owner_w(chunk); > > - if (chunk->shkey) > > - sctp_auth_shkey_release(chunk->shkey); > > + struct sctp_shared_key *shkey = chunk->shkey; > > + > > + if (chunk->msg) > > + sctp_set_owner_w(chunk); > > + else > > + sctp_control_set_owner_w(chunk); > > + > > + if (shkey) > > + sctp_auth_shkey_release(shkey); > > } > > [Severity: Medium] > > For control chunks with chunk->auth set, sctp_control_set_owner_w() always > does this: > > if (chunk->auth) { > chunk->shkey = asoc->shkey; > sctp_auth_shkey_hold(chunk->shkey); > } > > After peeloff/accept, a retained control chunk (an ASCONF-ACK, > addip_last_asconf or strreset_chunk) that was built under key K is > switched to whatever key is active at migration time. Is that intended? > > The DATA path through sctp_set_owner_w() keeps the key that was already > selected. The prerequisite shkey patch also describes the transfer as > keeping the selected authentication key. > > The commit message says: > > "since sctp_control_set_owner_w() may select a different asoc->shkey." > > It doesn't mention that retransmissions of these chunks would then be > authenticated with a different key id. > > Can this also lose the SCTP_AUTH_FREE_KEY event for K? Suppose K was > deactivated while chunk C still holds it, so K's refcnt is 2. K cannot > be the active key at that point, per sctp_auth_deact_key_id(): > > clear pass: > sctp_clear_owner_w() > sctp_auth_shkey_hold(K) K refcnt 3 > skb_orphan() > sctp_control_release_owner() sees refcnt 3, no event > sctp_auth_shkey_release(K) K refcnt 2 > > set pass: > sctp_set_owner_w_migrate() > sctp_control_set_owner_w() C->shkey = K', hold K' > sctp_auth_shkey_release(K) K refcnt 1 > > The last chunk reference on K is dropped by the plain > sctp_auth_shkey_release() in sctp_set_owner_w_migrate(). That call skips > the refcnt == 2 check, so no later code path sends SCTP_AUTH_FREE_KEY > for K. > > [ ... ] We should not allow sctp_control_set_owner_w() to select a different asoc->shkey if chunk->shkey already exists like in sctp_set_owner_w(), and we may need a change like: if (chunk->auth) { - chunk->shkey = asoc->shkey; + if (!chunk->shkey) + chunk->shkey = asoc->shkey; sctp_auth_shkey_hold(chunk->shkey); } in sctp_control_set_owner_w() for this issue. > > > @@ -198,6 +204,21 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc, > > > > list_for_each_entry(chunk, &q->out_chunk_list, list) > > traverse_and_process(); > > + > > + list_for_each_entry(chunk, &q->control_chunk_list, list) > > + cb(chunk); > > + > > + list_for_each_entry(chunk, &asoc->asconf_ack_list, transmitted_list) > > + cb(chunk); > > + > > + list_for_each_entry(chunk, &asoc->addip_chunk_list, list) > > + cb(chunk); > > + > > + if (asoc->strreset_chunk) > > + cb(asoc->strreset_chunk); > > + > > + if (asoc->addip_last_asconf) > > + cb(asoc->addip_last_asconf); > > } > > [Severity: High] > > These new walks call cb() without any filter. The DATA walks go through > traverse_and_process(), which checks c->skb->sk against asoc->base.sk so > each chunk is processed only once. Can a retained control chunk be > reachable from more than one of these lists or pointers at once? > > sctp_process_asconf() links the ASCONF-ACK on asconf_ack_list through > transmitted_list: > > sctp_chunk_hold(asconf_ack); > list_add_tail(&asconf_ack->transmitted_list, > &asoc->asconf_ack_list); > > sctp_sf_do_asconf() then queues the same chunk on control_chunk_list > through ->list with SCTP_CMD_REPLY. sctp_assoc_lookup_asconf_ack() > already skips entries where sctp_chunk_pending() is true, so being on > both lists is an expected state. > > strreset_chunk and addip_last_asconf are also queued on > control_chunk_list while the pointer is still held. > > These chunks can stay on control_chunk_list across a flush. > sctp_outq_flush_ctrl() skips them while src_out_of_asoc_ok is set, which > userspace can trigger through sctp_send_asconf_del_ip(): > > if (ctx->asoc->src_out_of_asoc_ok && > chunk->chunk_hdr->type != SCTP_CID_ASCONF) > continue; > > It also puts back chunks that fail to transmit: > > if (status != SCTP_XMIT_OK) { > /* put the chunk back */ > list_add(&chunk->list, &ctx->q->control_chunk_list); > > Take such a chunk with chunk->auth set, old key K and new key K'. The > refcounts go like this: > > clear pass, first visit: > sctp_clear_owner_w() hold K > skb_orphan() destructor releases K, clears destructor > clear pass, second visit: > sctp_clear_owner_w() hold K > skb_orphan() no destructor, nothing released > set pass, first visit: > sctp_set_owner_w_migrate() hold K', release K > set pass, second visit: > sctp_set_owner_w_migrate() hold K', release K' (chunk->shkey is K') > > Does this leak a reference on K? The net change is +1 on K. The struct > sctp_shared_key and its sctp_auth_bytes would then never be freed, and > the refcnt == 2 check in sctp_control_release_owner() could never fire > for K. > > A local user who controls both ends over loopback could repeat this for > each association. > > Could these walks skip chunks that were already handled, for example > with the same skb->sk check that traverse_and_process() uses? > It looks like bringing back sctp_process_tx_chunk() from your v2 patch will fix this. Sorry about it. Thanks. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-01 1:58 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-26 10:03 [PATCH net v3 0/2] sctp: re-point retained control chunks on association migration Jun Yang 2026-09-26 10:03 ` [PATCH net v3 1/2] sctp: hold shkey across socket migration Jun Yang 2026-09-30 0:06 ` netdev-bot+sashiko 2026-10-01 1:38 ` Xin Long 2026-09-26 10:03 ` [PATCH net v3 2/2] sctp: re-point retained control chunks on association migration Jun Yang 2026-09-30 0:06 ` netdev-bot+sashiko 2026-10-01 1:58 ` Xin Long
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox