From: Xin Long <lucien.xin@gmail.com>
To: network dev <netdev@vger.kernel.org>, linux-sctp@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Subject: [PATCH net v2 1/2] sctp: factor out INIT verification failure handling
Date: Sat, 20 Jun 2026 11:09:21 -0400 [thread overview]
Message-ID: <afa5f899e970da8efb28013293ec63fa19cd47b4.1781968162.git.lucien.xin@gmail.com> (raw)
In-Reply-To: <cover.1781968162.git.lucien.xin@gmail.com>
Extract the duplicated INIT/INIT-ACK error handling logic into a new
helper, sctp_abort_on_init_err().
Several state functions open-code the same pattern after
sctp_verify_init() fails: construct an ABORT with error causes if
available, send it when allocation succeeds, or fall back to T-bit ABORT
handling when no error chunk is present. INIT-ACK handling also includes
additional teardown logic for malformed packets.
Move this logic into sctp_abort_on_init_err() to reduce duplication and
centralize INIT/INIT-ACK failure handling.
No functional change intended. The helper will be used in a subsequent
patch.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
v2:
- Pass cid to sctp_abort_on_init_err().
- Delete chunk param from sctp_abort_on_init_err() and get chunk from
arg param.
- Jump to label 'out:' when err_chunk is NULL and cid is INIT_ACK in
sctp_abort_on_init_err(), noted by Sashiko.
---
net/sctp/sm_statefuns.c | 187 ++++++++++++++++++----------------------
1 file changed, 85 insertions(+), 102 deletions(-)
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 9b23c11cbb9e..8c636f045e45 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -68,6 +68,13 @@ static void sctp_send_stale_cookie_err(struct net *net,
const struct sctp_chunk *chunk,
struct sctp_cmd_seq *commands,
struct sctp_chunk *err_chunk);
+static enum sctp_disposition sctp_abort_on_init_err(
+ struct net *net,
+ const struct sctp_endpoint *ep,
+ const struct sctp_association *asoc,
+ enum sctp_cid cid, void *arg,
+ struct sctp_cmd_seq *commands,
+ struct sctp_chunk *err_chunk);
static enum sctp_disposition sctp_sf_do_5_2_6_stale(
struct net *net,
const struct sctp_endpoint *ep,
@@ -325,7 +332,7 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
struct sctp_chunk *chunk = arg, *repl, *err_chunk;
struct sctp_unrecognized_param *unk_param;
struct sctp_association *new_asoc;
- struct sctp_packet *packet;
+ enum sctp_cid cid;
int len;
/* 6.10 Bundling
@@ -373,34 +380,12 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
- if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
+ cid = chunk->chunk_hdr->type;
+ if (!sctp_verify_init(net, ep, asoc, cid,
(struct sctp_init_chunk *)chunk->chunk_hdr, chunk,
- &err_chunk)) {
- /* This chunk contains fatal error. It is to be discarded.
- * Send an ABORT, with causes if there is any.
- */
- if (err_chunk) {
- packet = sctp_abort_pkt_new(net, ep, asoc, arg,
- (__u8 *)(err_chunk->chunk_hdr) +
- sizeof(struct sctp_chunkhdr),
- ntohs(err_chunk->chunk_hdr->length) -
- sizeof(struct sctp_chunkhdr));
-
- sctp_chunk_free(err_chunk);
-
- if (packet) {
- sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
- SCTP_PACKET(packet));
- SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
- return SCTP_DISPOSITION_CONSUME;
- } else {
- return SCTP_DISPOSITION_NOMEM;
- }
- } else {
- return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg,
- commands);
- }
- }
+ &err_chunk))
+ return sctp_abort_on_init_err(net, ep, asoc, cid, arg, commands,
+ err_chunk);
/* Grab the INIT header. */
chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data;
@@ -525,7 +510,7 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net,
struct sctp_init_chunk *initchunk;
struct sctp_chunk *chunk = arg;
struct sctp_chunk *err_chunk;
- struct sctp_packet *packet;
+ enum sctp_cid cid;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -546,52 +531,12 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net,
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
- if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
+ cid = chunk->chunk_hdr->type;
+ if (!sctp_verify_init(net, ep, asoc, cid,
(struct sctp_init_chunk *)chunk->chunk_hdr, chunk,
- &err_chunk)) {
-
- enum sctp_error error = SCTP_ERROR_NO_RESOURCE;
-
- /* This chunk contains fatal error. It is to be discarded.
- * Send an ABORT, with causes. If there are no causes,
- * then there wasn't enough memory. Just terminate
- * the association.
- */
- if (err_chunk) {
- packet = sctp_abort_pkt_new(net, ep, asoc, arg,
- (__u8 *)(err_chunk->chunk_hdr) +
- sizeof(struct sctp_chunkhdr),
- ntohs(err_chunk->chunk_hdr->length) -
- sizeof(struct sctp_chunkhdr));
-
- sctp_chunk_free(err_chunk);
-
- if (packet) {
- sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
- SCTP_PACKET(packet));
- SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
- error = SCTP_ERROR_INV_PARAM;
- }
- }
-
- /* SCTP-AUTH, Section 6.3:
- * It should be noted that if the receiver wants to tear
- * down an association in an authenticated way only, the
- * handling of malformed packets should not result in
- * tearing down the association.
- *
- * This means that if we only want to abort associations
- * in an authenticated way (i.e AUTH+ABORT), then we
- * can't destroy this association just because the packet
- * was malformed.
- */
- if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
-
- SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
- return sctp_stop_t1_and_abort(net, commands, error, ECONNREFUSED,
- asoc, chunk->transport);
- }
+ &err_chunk))
+ return sctp_abort_on_init_err(net, ep, asoc, cid, arg, commands,
+ err_chunk);
/* Tag the variable length parameters. Note that we never
* convert the parameters in an INIT chunk.
@@ -1522,7 +1467,7 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
struct sctp_unrecognized_param *unk_param;
struct sctp_association *new_asoc;
enum sctp_disposition retval;
- struct sctp_packet *packet;
+ enum sctp_cid cid;
int len;
/* 6.10 Bundling
@@ -1564,33 +1509,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
- if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
+ cid = chunk->chunk_hdr->type;
+ if (!sctp_verify_init(net, ep, asoc, cid,
(struct sctp_init_chunk *)chunk->chunk_hdr, chunk,
- &err_chunk)) {
- /* This chunk contains fatal error. It is to be discarded.
- * Send an ABORT, with causes if there is any.
- */
- if (err_chunk) {
- packet = sctp_abort_pkt_new(net, ep, asoc, arg,
- (__u8 *)(err_chunk->chunk_hdr) +
- sizeof(struct sctp_chunkhdr),
- ntohs(err_chunk->chunk_hdr->length) -
- sizeof(struct sctp_chunkhdr));
-
- if (packet) {
- sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
- SCTP_PACKET(packet));
- SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
- retval = SCTP_DISPOSITION_CONSUME;
- } else {
- retval = SCTP_DISPOSITION_NOMEM;
- }
- goto cleanup;
- } else {
- return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg,
- commands);
- }
- }
+ &err_chunk))
+ return sctp_abort_on_init_err(net, ep, asoc, cid, arg, commands,
+ err_chunk);
/*
* Other parameters for the endpoint SHOULD be copied from the
@@ -1691,7 +1615,6 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
nomem_retval:
if (new_asoc)
sctp_association_free(new_asoc);
-cleanup:
if (err_chunk)
sctp_chunk_free(err_chunk);
return retval;
@@ -6485,6 +6408,66 @@ static void sctp_send_stale_cookie_err(struct net *net,
}
}
+static enum sctp_disposition sctp_abort_on_init_err(
+ struct net *net,
+ const struct sctp_endpoint *ep,
+ const struct sctp_association *asoc,
+ enum sctp_cid cid, void *arg,
+ struct sctp_cmd_seq *commands,
+ struct sctp_chunk *err_chunk)
+{
+ enum sctp_error error = SCTP_ERROR_NO_RESOURCE;
+ struct sctp_chunk *chunk = arg;
+ struct sctp_packet *packet;
+ struct sctp_chunkhdr *ch;
+
+ if (!err_chunk) {
+ if (cid == SCTP_CID_INIT_ACK)
+ goto out;
+ return sctp_sf_tabort_8_4_8(net, ep, asoc, SCTP_ST_CHUNK(0),
+ arg, commands);
+ }
+
+ ch = err_chunk->chunk_hdr;
+ packet = sctp_abort_pkt_new(net, ep, asoc, arg,
+ (__u8 *)ch + sizeof(*ch),
+ ntohs(ch->length) - sizeof(*ch));
+
+ sctp_chunk_free(err_chunk);
+
+ if (packet) {
+ sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
+ SCTP_PACKET(packet));
+ SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
+ error = SCTP_ERROR_INV_PARAM;
+ }
+
+ if (cid != SCTP_CID_INIT_ACK) {
+ if (!packet)
+ return SCTP_DISPOSITION_NOMEM;
+ return SCTP_DISPOSITION_CONSUME;
+ }
+
+out:
+ /* SCTP-AUTH, Section 6.3:
+ * It should be noted that if the receiver wants to tear
+ * down an association in an authenticated way only, the
+ * handling of malformed packets should not result in
+ * tearing down the association.
+ *
+ * This means that if we only want to abort associations
+ * in an authenticated way (i.e AUTH+ABORT), then we
+ * can't destroy this association just because the packet
+ * was malformed.
+ */
+ if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
+ return sctp_sf_pdiscard(net, ep, asoc, SCTP_ST_CHUNK(0), arg,
+ commands);
+
+ SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+ return sctp_stop_t1_and_abort(net, commands, error, ECONNREFUSED,
+ asoc, chunk->transport);
+}
/* Process a data chunk */
static int sctp_eat_data(const struct sctp_association *asoc,
--
2.47.1
next prev parent reply other threads:[~2026-06-20 15:10 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-20 15:09 [PATCH net v2 0/2] sctp: validate INIT in COOKIE-ECHO when auth disabled Xin Long
2026-06-20 15:09 ` Xin Long [this message]
2026-06-20 15:09 ` [PATCH net v2 2/2] sctp: add INIT verification after cookie unpacking Xin Long
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=afa5f899e970da8efb28013293ec63fa19cd47b4.1781968162.git.lucien.xin@gmail.com \
--to=lucien.xin@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-sctp@vger.kernel.org \
--cc=marcelo.leitner@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox