--- /dev/null
+From eae5783908042a762c24e1bd11876edb91d314b1 Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Wed, 20 Oct 2021 07:42:42 -0400
+Subject: sctp: fix the processing for INIT chunk
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit eae5783908042a762c24e1bd11876edb91d314b1 upstream.
+
+This patch fixes the problems below:
+
+1. In non-shutdown_ack_sent states: in sctp_sf_do_5_1B_init() and
+ sctp_sf_do_5_2_2_dupinit():
+
+ chunk length check should be done before any checks that may cause
+ to send abort, as making packet for abort will access the init_tag
+ from init_hdr in sctp_ootb_pkt_new().
+
+2. In shutdown_ack_sent state: in sctp_sf_do_9_2_reshutack():
+
+ The same checks as does in sctp_sf_do_5_2_2_dupinit() is needed
+ for sctp_sf_do_9_2_reshutack().
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sctp/sm_statefuns.c | 71 +++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 46 insertions(+), 25 deletions(-)
+
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -149,6 +149,12 @@ static enum sctp_disposition __sctp_sf_d
+ void *arg,
+ struct sctp_cmd_seq *commands);
+
++static enum sctp_disposition
++__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
++ const struct sctp_association *asoc,
++ const union sctp_subtype type, void *arg,
++ struct sctp_cmd_seq *commands);
++
+ /* Small helper function that checks if the chunk length
+ * is of the appropriate length. The 'required_length' argument
+ * is set to be the size of a specific chunk we are testing.
+@@ -330,6 +336,14 @@ enum sctp_disposition sctp_sf_do_5_1B_in
+ if (!chunk->singleton)
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+
++ /* Make sure that the INIT chunk has a valid length.
++ * Normally, this would cause an ABORT with a Protocol Violation
++ * error, but since we don't have an association, we'll
++ * just discard the packet.
++ */
++ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
++
+ /* If the packet is an OOTB packet which is temporarily on the
+ * control endpoint, respond with an ABORT.
+ */
+@@ -344,14 +358,6 @@ enum sctp_disposition sctp_sf_do_5_1B_in
+ if (chunk->sctp_hdr->vtag != 0)
+ return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
+
+- /* Make sure that the INIT chunk has a valid length.
+- * Normally, this would cause an ABORT with a Protocol Violation
+- * error, but since we don't have an association, we'll
+- * just discard the packet.
+- */
+- if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
+- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+-
+ /* If the INIT is coming toward a closing socket, we'll send back
+ * and ABORT. Essentially, this catches the race of INIT being
+ * backloged to the socket at the same time as the user isses close().
+@@ -1484,19 +1490,16 @@ static enum sctp_disposition sctp_sf_do_
+ if (!chunk->singleton)
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+
++ /* Make sure that the INIT chunk has a valid length. */
++ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
++
+ /* 3.1 A packet containing an INIT chunk MUST have a zero Verification
+ * Tag.
+ */
+ if (chunk->sctp_hdr->vtag != 0)
+ return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
+
+- /* Make sure that the INIT chunk has a valid length.
+- * In this case, we generate a protocol violation since we have
+- * an association established.
+- */
+- if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
+- return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
+- commands);
+ /* Grab the INIT header. */
+ chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data;
+
+@@ -1814,9 +1817,9 @@ static enum sctp_disposition sctp_sf_do_
+ * its peer.
+ */
+ if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) {
+- disposition = sctp_sf_do_9_2_reshutack(net, ep, asoc,
+- SCTP_ST_CHUNK(chunk->chunk_hdr->type),
+- chunk, commands);
++ disposition = __sctp_sf_do_9_2_reshutack(net, ep, asoc,
++ SCTP_ST_CHUNK(chunk->chunk_hdr->type),
++ chunk, commands);
+ if (SCTP_DISPOSITION_NOMEM == disposition)
+ goto nomem;
+
+@@ -2915,13 +2918,11 @@ enum sctp_disposition sctp_sf_do_9_2_shu
+ * that belong to this association, it should discard the INIT chunk and
+ * retransmit the SHUTDOWN ACK chunk.
+ */
+-enum sctp_disposition sctp_sf_do_9_2_reshutack(
+- struct net *net,
+- const struct sctp_endpoint *ep,
+- const struct sctp_association *asoc,
+- const union sctp_subtype type,
+- void *arg,
+- struct sctp_cmd_seq *commands)
++static enum sctp_disposition
++__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
++ const struct sctp_association *asoc,
++ const union sctp_subtype type, void *arg,
++ struct sctp_cmd_seq *commands)
+ {
+ struct sctp_chunk *chunk = arg;
+ struct sctp_chunk *reply;
+@@ -2955,6 +2956,26 @@ nomem:
+ return SCTP_DISPOSITION_NOMEM;
+ }
+
++enum sctp_disposition
++sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep,
++ const struct sctp_association *asoc,
++ const union sctp_subtype type, void *arg,
++ struct sctp_cmd_seq *commands)
++{
++ struct sctp_chunk *chunk = arg;
++
++ if (!chunk->singleton)
++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
++
++ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk)))
++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
++
++ if (chunk->sctp_hdr->vtag != 0)
++ return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
++
++ return __sctp_sf_do_9_2_reshutack(net, ep, asoc, type, arg, commands);
++}
++
+ /*
+ * sctp_sf_do_ecn_cwr
+ *