]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Mar 2022 14:25:10 +0000 (15:25 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Mar 2022 14:25:10 +0000 (15:25 +0100)
added patches:
sctp-fix-the-processing-for-init-chunk.patch
sctp-fix-the-processing-for-init_ack-chunk.patch

queue-4.14/sctp-fix-the-processing-for-init-chunk.patch [new file with mode: 0644]
queue-4.14/sctp-fix-the-processing-for-init_ack-chunk.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/sctp-fix-the-processing-for-init-chunk.patch b/queue-4.14/sctp-fix-the-processing-for-init-chunk.patch
new file mode 100644 (file)
index 0000000..04e6715
--- /dev/null
@@ -0,0 +1,161 @@
+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
+@@ -161,6 +161,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.
+@@ -337,6 +343,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.
+        */
+@@ -351,14 +365,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().
+@@ -1460,19 +1466,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;
+@@ -1787,9 +1790,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;
+@@ -2847,13 +2850,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;
+@@ -2887,6 +2888,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
+  *
diff --git a/queue-4.14/sctp-fix-the-processing-for-init_ack-chunk.patch b/queue-4.14/sctp-fix-the-processing-for-init_ack-chunk.patch
new file mode 100644 (file)
index 0000000..404abdf
--- /dev/null
@@ -0,0 +1,131 @@
+From 438b95a7c98f77d51cbf4db021f41b602d750a3f Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Wed, 20 Oct 2021 07:42:43 -0400
+Subject: sctp: fix the processing for INIT_ACK chunk
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit 438b95a7c98f77d51cbf4db021f41b602d750a3f upstream.
+
+Currently INIT_ACK chunk in non-cookie_echoed state is processed in
+sctp_sf_discard_chunk() to send an abort with the existent asoc's
+vtag if the chunk length is not valid. But the vtag in the chunk's
+sctphdr is not verified, which may be exploited by one to cook a
+malicious chunk to terminal a SCTP asoc.
+
+sctp_sf_discard_chunk() also is called in many other places to send
+an abort, and most of those have this problem. This patch is to fix
+it by sending abort with the existent asoc's vtag only if the vtag
+from the chunk's sctphdr is verified in sctp_sf_discard_chunk().
+
+Note on sctp_sf_do_9_1_abort() and sctp_sf_shutdown_pending_abort(),
+the chunk length has been verified before sctp_sf_discard_chunk(),
+so replace it with sctp_sf_discard(). On sctp_sf_do_asconf_ack() and
+sctp_sf_do_asconf(), move the sctp_chunk_length_valid check ahead of
+sctp_sf_discard_chunk(), then replace it with sctp_sf_discard().
+
+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 |   37 +++++++++++++++++++------------------
+ 1 file changed, 19 insertions(+), 18 deletions(-)
+
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -2221,7 +2221,7 @@ enum sctp_disposition sctp_sf_shutdown_p
+        */
+       if (SCTP_ADDR_DEL ==
+                   sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
+-              return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
++              return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       if (!sctp_err_chunk_valid(chunk))
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+@@ -2267,7 +2267,7 @@ enum sctp_disposition sctp_sf_shutdown_s
+        */
+       if (SCTP_ADDR_DEL ==
+                   sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
+-              return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
++              return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       if (!sctp_err_chunk_valid(chunk))
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+@@ -2537,7 +2537,7 @@ enum sctp_disposition sctp_sf_do_9_1_abo
+        */
+       if (SCTP_ADDR_DEL ==
+                   sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
+-              return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
++              return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       if (!sctp_err_chunk_valid(chunk))
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+@@ -3702,6 +3702,11 @@ enum sctp_disposition sctp_sf_do_asconf(
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       }
++      /* Make sure that the ASCONF ADDIP chunk has a valid length.  */
++      if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_addip_chunk)))
++              return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
++                                                commands);
++
+       /* ADD-IP: Section 4.1.1
+        * This chunk MUST be sent in an authenticated way by using
+        * the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk
+@@ -3709,13 +3714,7 @@ enum sctp_disposition sctp_sf_do_asconf(
+        * described in [I-D.ietf-tsvwg-sctp-auth].
+        */
+       if (!net->sctp.addip_noauth && !chunk->auth)
+-              return sctp_sf_discard_chunk(net, ep, asoc, type, arg,
+-                                           commands);
+-
+-      /* Make sure that the ASCONF ADDIP chunk has a valid length.  */
+-      if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_addip_chunk)))
+-              return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
+-                                                commands);
++              return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       hdr = (struct sctp_addiphdr *)chunk->skb->data;
+       serial = ntohl(hdr->serial);
+@@ -3844,6 +3843,12 @@ enum sctp_disposition sctp_sf_do_asconf_
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       }
++      /* Make sure that the ADDIP chunk has a valid length.  */
++      if (!sctp_chunk_length_valid(asconf_ack,
++                                   sizeof(struct sctp_addip_chunk)))
++              return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
++                                                commands);
++
+       /* ADD-IP, Section 4.1.2:
+        * This chunk MUST be sent in an authenticated way by using
+        * the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk
+@@ -3851,14 +3856,7 @@ enum sctp_disposition sctp_sf_do_asconf_
+        * described in [I-D.ietf-tsvwg-sctp-auth].
+        */
+       if (!net->sctp.addip_noauth && !asconf_ack->auth)
+-              return sctp_sf_discard_chunk(net, ep, asoc, type, arg,
+-                                           commands);
+-
+-      /* Make sure that the ADDIP chunk has a valid length.  */
+-      if (!sctp_chunk_length_valid(asconf_ack,
+-                                   sizeof(struct sctp_addip_chunk)))
+-              return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
+-                                                commands);
++              return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+       addip_hdr = (struct sctp_addiphdr *)asconf_ack->skb->data;
+       rcvd_serial = ntohl(addip_hdr->serial);
+@@ -4435,6 +4433,9 @@ enum sctp_disposition sctp_sf_discard_ch
+ {
+       struct sctp_chunk *chunk = arg;
++      if (asoc && !sctp_vtag_verify(chunk, asoc))
++              return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
++
+       /* Make sure that the chunk has a valid length.
+        * Since we don't know the chunk type, we use a general
+        * chunkhdr structure to make a comparison.
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9d3127380d485346daff2b10de1b0d32714f5c25 100644 (file)
@@ -0,0 +1,2 @@
+sctp-fix-the-processing-for-init-chunk.patch
+sctp-fix-the-processing-for-init_ack-chunk.patch