From f6140efad11a8a319571b0692f45731662814918 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 16 Mar 2022 15:25:10 +0100 Subject: [PATCH] 4.14-stable patches added patches: sctp-fix-the-processing-for-init-chunk.patch sctp-fix-the-processing-for-init_ack-chunk.patch --- ...tp-fix-the-processing-for-init-chunk.patch | 161 ++++++++++++++++++ ...ix-the-processing-for-init_ack-chunk.patch | 131 ++++++++++++++ queue-4.14/series | 2 + 3 files changed, 294 insertions(+) create mode 100644 queue-4.14/sctp-fix-the-processing-for-init-chunk.patch create mode 100644 queue-4.14/sctp-fix-the-processing-for-init_ack-chunk.patch 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 index 00000000000..04e67156e26 --- /dev/null +++ b/queue-4.14/sctp-fix-the-processing-for-init-chunk.patch @@ -0,0 +1,161 @@ +From eae5783908042a762c24e1bd11876edb91d314b1 Mon Sep 17 00:00:00 2001 +From: Xin Long +Date: Wed, 20 Oct 2021 07:42:42 -0400 +Subject: sctp: fix the processing for INIT chunk + +From: Xin Long + +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 +Acked-by: Marcelo Ricardo Leitner +Signed-off-by: Jakub Kicinski +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..404abdf76a1 --- /dev/null +++ b/queue-4.14/sctp-fix-the-processing-for-init_ack-chunk.patch @@ -0,0 +1,131 @@ +From 438b95a7c98f77d51cbf4db021f41b602d750a3f Mon Sep 17 00:00:00 2001 +From: Xin Long +Date: Wed, 20 Oct 2021 07:42:43 -0400 +Subject: sctp: fix the processing for INIT_ACK chunk + +From: Xin Long + +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 +Acked-by: Marcelo Ricardo Leitner +Signed-off-by: Jakub Kicinski +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + 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. diff --git a/queue-4.14/series b/queue-4.14/series index e69de29bb2d..9d3127380d4 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -0,0 +1,2 @@ +sctp-fix-the-processing-for-init-chunk.patch +sctp-fix-the-processing-for-init_ack-chunk.patch -- 2.47.3