From: Jun Yang <juny24602@gmail.com>
To: netdev@vger.kernel.org
Cc: Jun Yang <junvyyang@tencent.com>,
stable@kernel.org, TencentOS Corvus AI <corvus@tencent.com>,
Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>,
Xin Long <lucien.xin@gmail.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
linux-sctp@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH net] sctp: fix stream->outcnt underflow on duplicate RECONF responses
Date: Thu, 30 Jul 2026 19:02:19 +0800 [thread overview]
Message-ID: <20260730110225.37371-1-juny24602@gmail.com> (raw)
From: Jun Yang <junvyyang@tencent.com>
sctp_process_strreset_resp() rolls back a denied ADD_OUT_STREAMS request
by subtracting the requested count from the current stream count:
nums = ntohs(addstrm->number_of_streams);
number = stream->outcnt - nums; /* net/sctp/stream.c:1050 */
...
stream->outcnt = number; /* net/sctp/stream.c:1060 */
This undoes the increment sctp_send_add_streams() performed at request
time, and is only correct if it runs exactly once per request. Nothing
enforces that.
The function does not check asoc->strreset_outstanding on entry; it only
decrements it at the tail, and asoc->strreset_chunk - the only thing
sctp_chunk_lookup_strreset_param() consults - stays live until that
counter reaches zero. When both outgoing and incoming streams are added
in one setsockopt(SCTP_ADD_STREAMS), sctp_send_add_streams() sets
strreset_outstanding to 2 and caches a chunk holding both the ADD_OUT
and ADD_IN parameters.
sctp_verify_reconf() permits a RESET_RESPONSE to follow another
RESET_RESPONSE, and the lookup accepts any request still present in the
cached chunk. A peer can therefore put two responses carrying the
ADD_OUT request_seq into a single RECONF chunk. sctp_sf_do_reconf()
processes both: the first rollback restores the original count and the
second subtracts nums again. Depending on the counts, this either wraps
the __u16 or silently shrinks the stream count a second time.
SCTP_SO() is genradix_ptr(), which returns NULL past the preallocated
range, so sctp_sendmsg_to_asoc() accepts an out-of-range stream id at
net/sctp/socket.c:1803 and dereferences the resulting NULL slot at
net/sctp/socket.c:1808. Other stream walkers likewise trust the
inflated count until a later operation repairs or tears down the
association.
Only accept the response sequence currently named by strreset_outseq.
Each accepted response advances that sequence, so a duplicate becomes
stale even while another request parameter remains outstanding. Also
reject a response whose count exceeds the current stream count as a
defence-in-depth check on the subtraction.
Fixes: 11ae76e67a17 ("sctp: implement receiver-side procedures for the Reconf Response Parameter")
Cc: stable@kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Signed-off-by: Jun Yang <junvyyang@tencent.com>
---
net/sctp/stream.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 34ffe6c945a4..b751d0843b3d 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -927,6 +927,14 @@ struct sctp_chunk *sctp_process_strreset_resp(
struct sctp_paramhdr *req;
__u32 result;
+ /* Process responses in request sequence. strreset_outseq advances after
+ * each accepted response, so this also rejects duplicate responses while
+ * another parameter from the same RECONF chunk remains outstanding.
+ */
+ if (!asoc->strreset_outstanding ||
+ resp->response_seq != htonl(asoc->strreset_outseq))
+ return NULL;
+
req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
if (!req)
return NULL;
@@ -1047,6 +1055,8 @@ struct sctp_chunk *sctp_process_strreset_resp(
addstrm = (struct sctp_strreset_addstrm *)req;
nums = ntohs(addstrm->number_of_streams);
+ if (nums > stream->outcnt)
+ return NULL;
number = stream->outcnt - nums;
if (result == SCTP_STRRESET_PERFORMED) {
--
2.55.0
reply other threads:[~2026-07-30 11:02 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260730110225.37371-1-juny24602@gmail.com \
--to=juny24602@gmail.com \
--cc=corvus@tencent.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=junvyyang@tencent.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sctp@vger.kernel.org \
--cc=lucien.xin@gmail.com \
--cc=marcelo.leitner@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.