From: Sasha Levin Date: Sat, 30 Oct 2021 20:33:18 +0000 (-0400) Subject: Fixes for 5.10 X-Git-Tag: v4.4.291~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f0b11b6888cc60f55bfe78b98d870882e0188ba6;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/lan743x-fix-endianness-when-accessing-descriptors.patch b/queue-5.10/lan743x-fix-endianness-when-accessing-descriptors.patch new file mode 100644 index 00000000000..3177868f179 --- /dev/null +++ b/queue-5.10/lan743x-fix-endianness-when-accessing-descriptors.patch @@ -0,0 +1,272 @@ +From 37b729bfdcae86ae5b93ebc044ca9215744fc43b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Jan 2021 09:48:59 +0500 +Subject: lan743x: fix endianness when accessing descriptors + +From: Alexey Denisov + +[ Upstream commit 462512824f902a24de794290dd622e664587da1d ] + +TX/RX descriptor ring fields are always little-endian, but conversion +wasn't performed for big-endian CPUs, so the driver failed to work. + +This patch makes the driver work on big-endian CPUs. It was tested and +confirmed to work on NXP P1010 processor (PowerPC). + +Signed-off-by: Alexey Denisov +Link: https://lore.kernel.org/r/20210128044859.280219-1-rtgbnm@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microchip/lan743x_main.c | 66 +++++++++---------- + drivers/net/ethernet/microchip/lan743x_main.h | 20 +++--- + 2 files changed, 43 insertions(+), 43 deletions(-) + +diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c +index 3355e0a5b272..e14dfaafe439 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.c ++++ b/drivers/net/ethernet/microchip/lan743x_main.c +@@ -1280,7 +1280,7 @@ static void lan743x_tx_release_desc(struct lan743x_tx *tx, + if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_ACTIVE)) + goto done; + +- descriptor_type = (descriptor->data0) & ++ descriptor_type = le32_to_cpu(descriptor->data0) & + TX_DESC_DATA0_DTYPE_MASK_; + if (descriptor_type == TX_DESC_DATA0_DTYPE_DATA_) + goto clean_up_data_descriptor; +@@ -1340,7 +1340,7 @@ static int lan743x_tx_next_index(struct lan743x_tx *tx, int index) + + static void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx) + { +- while ((*tx->head_cpu_ptr) != (tx->last_head)) { ++ while (le32_to_cpu(*tx->head_cpu_ptr) != (tx->last_head)) { + lan743x_tx_release_desc(tx, tx->last_head, false); + tx->last_head = lan743x_tx_next_index(tx, tx->last_head); + } +@@ -1426,10 +1426,10 @@ static int lan743x_tx_frame_start(struct lan743x_tx *tx, + if (dma_mapping_error(dev, dma_ptr)) + return -ENOMEM; + +- tx_descriptor->data1 = DMA_ADDR_LOW32(dma_ptr); +- tx_descriptor->data2 = DMA_ADDR_HIGH32(dma_ptr); +- tx_descriptor->data3 = (frame_length << 16) & +- TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_; ++ tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr)); ++ tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr)); ++ tx_descriptor->data3 = cpu_to_le32((frame_length << 16) & ++ TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_); + + buffer_info->skb = NULL; + buffer_info->dma_ptr = dma_ptr; +@@ -1470,7 +1470,7 @@ static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx, + tx->frame_data0 |= TX_DESC_DATA0_IOC_; + } + tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; +- tx_descriptor->data0 = tx->frame_data0; ++ tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); + + /* move to next descriptor */ + tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); +@@ -1514,7 +1514,7 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx, + + /* wrap up previous descriptor */ + tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail]; +- tx_descriptor->data0 = tx->frame_data0; ++ tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); + + /* move to next descriptor */ + tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); +@@ -1540,10 +1540,10 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx, + return -ENOMEM; + } + +- tx_descriptor->data1 = DMA_ADDR_LOW32(dma_ptr); +- tx_descriptor->data2 = DMA_ADDR_HIGH32(dma_ptr); +- tx_descriptor->data3 = (frame_length << 16) & +- TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_; ++ tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr)); ++ tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr)); ++ tx_descriptor->data3 = cpu_to_le32((frame_length << 16) & ++ TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_); + + buffer_info->skb = NULL; + buffer_info->dma_ptr = dma_ptr; +@@ -1587,7 +1587,7 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx, + if (ignore_sync) + buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC; + +- tx_descriptor->data0 = tx->frame_data0; ++ tx_descriptor->data0 = cpu_to_le32(tx->frame_data0); + tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail); + tx->last_tail = tx->frame_tail; + +@@ -2004,11 +2004,11 @@ static int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index, + } + + buffer_info->buffer_length = length; +- descriptor->data1 = DMA_ADDR_LOW32(buffer_info->dma_ptr); +- descriptor->data2 = DMA_ADDR_HIGH32(buffer_info->dma_ptr); ++ descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr)); ++ descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr)); + descriptor->data3 = 0; +- descriptor->data0 = (RX_DESC_DATA0_OWN_ | +- (length & RX_DESC_DATA0_BUF_LENGTH_MASK_)); ++ descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ | ++ (length & RX_DESC_DATA0_BUF_LENGTH_MASK_))); + skb_reserve(buffer_info->skb, RX_HEAD_PADDING); + lan743x_rx_update_tail(rx, index); + +@@ -2023,12 +2023,12 @@ static void lan743x_rx_reuse_ring_element(struct lan743x_rx *rx, int index) + descriptor = &rx->ring_cpu_ptr[index]; + buffer_info = &rx->buffer_info[index]; + +- descriptor->data1 = DMA_ADDR_LOW32(buffer_info->dma_ptr); +- descriptor->data2 = DMA_ADDR_HIGH32(buffer_info->dma_ptr); ++ descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr)); ++ descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr)); + descriptor->data3 = 0; +- descriptor->data0 = (RX_DESC_DATA0_OWN_ | ++ descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ | + ((buffer_info->buffer_length) & +- RX_DESC_DATA0_BUF_LENGTH_MASK_)); ++ RX_DESC_DATA0_BUF_LENGTH_MASK_))); + lan743x_rx_update_tail(rx, index); + } + +@@ -2062,7 +2062,7 @@ static int lan743x_rx_process_packet(struct lan743x_rx *rx) + { + struct skb_shared_hwtstamps *hwtstamps = NULL; + int result = RX_PROCESS_RESULT_NOTHING_TO_DO; +- int current_head_index = *rx->head_cpu_ptr; ++ int current_head_index = le32_to_cpu(*rx->head_cpu_ptr); + struct lan743x_rx_buffer_info *buffer_info; + struct lan743x_rx_descriptor *descriptor; + int extension_index = -1; +@@ -2077,14 +2077,14 @@ static int lan743x_rx_process_packet(struct lan743x_rx *rx) + + if (rx->last_head != current_head_index) { + descriptor = &rx->ring_cpu_ptr[rx->last_head]; +- if (descriptor->data0 & RX_DESC_DATA0_OWN_) ++ if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_) + goto done; + +- if (!(descriptor->data0 & RX_DESC_DATA0_FS_)) ++ if (!(le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_FS_)) + goto done; + + first_index = rx->last_head; +- if (descriptor->data0 & RX_DESC_DATA0_LS_) { ++ if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_) { + last_index = rx->last_head; + } else { + int index; +@@ -2092,10 +2092,10 @@ static int lan743x_rx_process_packet(struct lan743x_rx *rx) + index = lan743x_rx_next_index(rx, first_index); + while (index != current_head_index) { + descriptor = &rx->ring_cpu_ptr[index]; +- if (descriptor->data0 & RX_DESC_DATA0_OWN_) ++ if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_) + goto done; + +- if (descriptor->data0 & RX_DESC_DATA0_LS_) { ++ if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_) { + last_index = index; + break; + } +@@ -2104,17 +2104,17 @@ static int lan743x_rx_process_packet(struct lan743x_rx *rx) + } + if (last_index >= 0) { + descriptor = &rx->ring_cpu_ptr[last_index]; +- if (descriptor->data0 & RX_DESC_DATA0_EXT_) { ++ if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_EXT_) { + /* extension is expected to follow */ + int index = lan743x_rx_next_index(rx, + last_index); + if (index != current_head_index) { + descriptor = &rx->ring_cpu_ptr[index]; +- if (descriptor->data0 & ++ if (le32_to_cpu(descriptor->data0) & + RX_DESC_DATA0_OWN_) { + goto done; + } +- if (descriptor->data0 & ++ if (le32_to_cpu(descriptor->data0) & + RX_DESC_DATA0_EXT_) { + extension_index = index; + } else { +@@ -2166,7 +2166,7 @@ static int lan743x_rx_process_packet(struct lan743x_rx *rx) + } + buffer_info->skb = NULL; + packet_length = RX_DESC_DATA0_FRAME_LENGTH_GET_ +- (descriptor->data0); ++ (le32_to_cpu(descriptor->data0)); + skb_put(skb, packet_length - 4); + skb->protocol = eth_type_trans(skb, + rx->adapter->netdev); +@@ -2204,8 +2204,8 @@ process_extension: + descriptor = &rx->ring_cpu_ptr[extension_index]; + buffer_info = &rx->buffer_info[extension_index]; + +- ts_sec = descriptor->data1; +- ts_nsec = (descriptor->data2 & ++ ts_sec = le32_to_cpu(descriptor->data1); ++ ts_nsec = (le32_to_cpu(descriptor->data2) & + RX_DESC_DATA2_TS_NS_MASK_); + lan743x_rx_reuse_ring_element(rx, extension_index); + real_last_index = extension_index; +diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h +index a536f4a4994d..751f2bc9ce84 100644 +--- a/drivers/net/ethernet/microchip/lan743x_main.h ++++ b/drivers/net/ethernet/microchip/lan743x_main.h +@@ -660,7 +660,7 @@ struct lan743x_tx { + + struct lan743x_tx_buffer_info *buffer_info; + +- u32 *head_cpu_ptr; ++ __le32 *head_cpu_ptr; + dma_addr_t head_dma_ptr; + int last_head; + int last_tail; +@@ -690,7 +690,7 @@ struct lan743x_rx { + + struct lan743x_rx_buffer_info *buffer_info; + +- u32 *head_cpu_ptr; ++ __le32 *head_cpu_ptr; + dma_addr_t head_dma_ptr; + u32 last_head; + u32 last_tail; +@@ -775,10 +775,10 @@ struct lan743x_adapter { + #define TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_ (0x3FFF0000) + + struct lan743x_tx_descriptor { +- u32 data0; +- u32 data1; +- u32 data2; +- u32 data3; ++ __le32 data0; ++ __le32 data1; ++ __le32 data2; ++ __le32 data3; + } __aligned(DEFAULT_DMA_DESCRIPTOR_SPACING); + + #define TX_BUFFER_INFO_FLAG_ACTIVE BIT(0) +@@ -813,10 +813,10 @@ struct lan743x_tx_buffer_info { + #define RX_HEAD_PADDING NET_IP_ALIGN + + struct lan743x_rx_descriptor { +- u32 data0; +- u32 data1; +- u32 data2; +- u32 data3; ++ __le32 data0; ++ __le32 data1; ++ __le32 data2; ++ __le32 data3; + } __aligned(DEFAULT_DMA_DESCRIPTOR_SPACING); + + #define RX_BUFFER_INFO_FLAG_ACTIVE BIT(0) +-- +2.33.0 + diff --git a/queue-5.10/sctp-add-vtag-check-in-sctp_sf_do_8_5_1_e_sa.patch b/queue-5.10/sctp-add-vtag-check-in-sctp_sf_do_8_5_1_e_sa.patch new file mode 100644 index 00000000000..797dbe8b903 --- /dev/null +++ b/queue-5.10/sctp-add-vtag-check-in-sctp_sf_do_8_5_1_e_sa.patch @@ -0,0 +1,65 @@ +From 2c242ee05566874e7f29e64442c5e48de9bf72d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Oct 2021 07:42:46 -0400 +Subject: sctp: add vtag check in sctp_sf_do_8_5_1_E_sa + +From: Xin Long + +[ Upstream commit ef16b1734f0a176277b7bb9c71a6d977a6ef3998 ] + +sctp_sf_do_8_5_1_E_sa() is called when processing SHUTDOWN_ACK chunk +in cookie_wait and cookie_echoed state. + +The vtag in the chunk's sctphdr should be verified, otherwise, as +later in chunk length check, it may send abort with the existent +asoc's vtag, which can be exploited by one to cook a malicious +chunk to terminate a SCTP asoc. + +Note that when fails to verify the vtag from SHUTDOWN-ACK chunk, +SHUTDOWN COMPLETE message will still be sent back to peer, but +with the vtag from SHUTDOWN-ACK chunk, as said in 5) of +rfc4960#section-8.4. + +While at it, also remove the unnecessary chunk length check from +sctp_sf_shut_8_4_5(), as it's already done in both places where +it calls sctp_sf_shut_8_4_5(). + +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: Sasha Levin +--- + net/sctp/sm_statefuns.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 324c0222d9e6..82a76fda226b 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -3683,12 +3683,6 @@ static enum sctp_disposition sctp_sf_shut_8_4_5( + + SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS); + +- /* If the chunk length is invalid, we don't want to process +- * the reset of the packet. +- */ +- if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) +- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); +- + /* We need to discard the rest of the packet to prevent + * potential bomming attacks from additional bundled chunks. + * This is documented in SCTP Threats ID. +@@ -3716,6 +3710,9 @@ enum sctp_disposition sctp_sf_do_8_5_1_E_sa(struct net *net, + { + struct sctp_chunk *chunk = arg; + ++ if (!sctp_vtag_verify(chunk, asoc)) ++ asoc = NULL; ++ + /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */ + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) + return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, +-- +2.33.0 + diff --git a/queue-5.10/sctp-add-vtag-check-in-sctp_sf_ootb.patch b/queue-5.10/sctp-add-vtag-check-in-sctp_sf_ootb.patch new file mode 100644 index 00000000000..bf946a85f4f --- /dev/null +++ b/queue-5.10/sctp-add-vtag-check-in-sctp_sf_ootb.patch @@ -0,0 +1,47 @@ +From 94f1f57da0e8608e56d71c42d65b20cc013f80de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Oct 2021 07:42:47 -0400 +Subject: sctp: add vtag check in sctp_sf_ootb + +From: Xin Long + +[ Upstream commit 9d02831e517aa36ee6bdb453a0eb47bd49923fe3 ] + +sctp_sf_ootb() is called when processing DATA chunk in closed state, +and many other places are also using it. + +The vtag in the chunk's sctphdr should be verified, otherwise, as +later in chunk length check, it may send abort with the existent +asoc's vtag, which can be exploited by one to cook a malicious +chunk to terminate a SCTP asoc. + +When fails to verify the vtag from the chunk, this patch sets asoc +to NULL, so that the abort will be made with the vtag from the +received chunk later. + +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: Sasha Levin +--- + net/sctp/sm_statefuns.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 82a76fda226b..096e6be1d8fc 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -3568,6 +3568,9 @@ enum sctp_disposition sctp_sf_ootb(struct net *net, + + SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES); + ++ if (asoc && !sctp_vtag_verify(chunk, asoc)) ++ asoc = NULL; ++ + ch = (struct sctp_chunkhdr *)chunk->chunk_hdr; + do { + /* Report violation if the chunk is less then minimal */ +-- +2.33.0 + diff --git a/queue-5.10/sctp-add-vtag-check-in-sctp_sf_violation.patch b/queue-5.10/sctp-add-vtag-check-in-sctp_sf_violation.patch new file mode 100644 index 00000000000..8206f03b26d --- /dev/null +++ b/queue-5.10/sctp-add-vtag-check-in-sctp_sf_violation.patch @@ -0,0 +1,43 @@ +From 310232774f6bc3bc53669b6678c91c646154f1c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Oct 2021 07:42:45 -0400 +Subject: sctp: add vtag check in sctp_sf_violation + +From: Xin Long + +[ Upstream commit aa0f697e45286a6b5f0ceca9418acf54b9099d99 ] + +sctp_sf_violation() is called when processing HEARTBEAT_ACK chunk +in cookie_wait state, and some other places are also using it. + +The vtag in the chunk's sctphdr should be verified, otherwise, as +later in chunk length check, it may send abort with the existent +asoc's vtag, which can be exploited by one to cook a malicious +chunk to terminate a SCTP asoc. + +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: Sasha Levin +--- + net/sctp/sm_statefuns.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 0cfbf6046bf8..324c0222d9e6 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -4549,6 +4549,9 @@ enum sctp_disposition sctp_sf_violation(struct net *net, + { + struct sctp_chunk *chunk = arg; + ++ if (!sctp_vtag_verify(chunk, asoc)) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ + /* Make sure that the chunk has a valid length. */ + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) + return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, +-- +2.33.0 + diff --git a/queue-5.10/sctp-fix-the-processing-for-cookie_echo-chunk.patch b/queue-5.10/sctp-fix-the-processing-for-cookie_echo-chunk.patch new file mode 100644 index 00000000000..86025929be4 --- /dev/null +++ b/queue-5.10/sctp-fix-the-processing-for-cookie_echo-chunk.patch @@ -0,0 +1,75 @@ +From cb7de9600b3a64f23f0e851ee878c16e5d5f594c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Oct 2021 07:42:44 -0400 +Subject: sctp: fix the processing for COOKIE_ECHO chunk + +From: Xin Long + +[ Upstream commit a64b341b8695e1c744dd972b39868371b4f68f83 ] + +1. In closed state: in sctp_sf_do_5_1D_ce(): + + When asoc is NULL, making packet for abort will use chunk's vtag + in sctp_ootb_pkt_new(). But when asoc exists, vtag from the chunk + should be verified before using peer.i.init_tag to make packet + for abort in sctp_ootb_pkt_new(), and just discard it if vtag is + not correct. + +2. In the other states: in sctp_sf_do_5_2_4_dupcook(): + + asoc always exists, but duplicate cookie_echo's vtag will be + handled by sctp_tietags_compare() and then take actions, so before + that we only verify the vtag for the abort sent for invalid chunk + length. + +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: Sasha Levin +--- + net/sctp/sm_statefuns.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 5063f9884367..0cfbf6046bf8 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -697,6 +697,9 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net, + struct sock *sk; + int error = 0; + ++ if (asoc && !sctp_vtag_verify(chunk, asoc)) ++ 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. + */ +@@ -711,7 +714,8 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net, + * in sctp_unpack_cookie(). + */ + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) +- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, ++ commands); + + /* If the endpoint is not listening or if the number of associations + * on the TCP-style socket exceed the max backlog, respond with an +@@ -2141,9 +2145,11 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook( + * enough for the chunk header. Cookie length verification is + * done later. + */ +- if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) +- return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, +- commands); ++ if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_chunkhdr))) { ++ if (!sctp_vtag_verify(chunk, asoc)) ++ asoc = NULL; ++ return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, commands); ++ } + + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. +-- +2.33.0 + diff --git a/queue-5.10/sctp-fix-the-processing-for-init_ack-chunk.patch b/queue-5.10/sctp-fix-the-processing-for-init_ack-chunk.patch new file mode 100644 index 00000000000..61c4d9806d4 --- /dev/null +++ b/queue-5.10/sctp-fix-the-processing-for-init_ack-chunk.patch @@ -0,0 +1,135 @@ +From 1d539cf9008b54ccd9ccd456d52b1cc3237fbe76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Oct 2021 07:42:43 -0400 +Subject: sctp: fix the processing for INIT_ACK chunk + +From: Xin Long + +[ Upstream commit 438b95a7c98f77d51cbf4db021f41b602d750a3f ] + +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: Sasha Levin +--- + net/sctp/sm_statefuns.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 89a86728184d..5063f9884367 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -2280,7 +2280,7 @@ enum sctp_disposition sctp_sf_shutdown_pending_abort( + */ + 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); +@@ -2326,7 +2326,7 @@ enum sctp_disposition sctp_sf_shutdown_sent_abort( + */ + 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); +@@ -2596,7 +2596,7 @@ enum sctp_disposition sctp_sf_do_9_1_abort( + */ + 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); +@@ -3745,6 +3745,11 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net, + 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 +@@ -3753,13 +3758,7 @@ enum sctp_disposition sctp_sf_do_asconf(struct net *net, + */ + if (!asoc->peer.asconf_capable || + (!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); +@@ -3888,6 +3887,12 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net, + 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 +@@ -3896,14 +3901,7 @@ enum sctp_disposition sctp_sf_do_asconf_ack(struct net *net, + */ + if (!asoc->peer.asconf_capable || + (!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); +@@ -4475,6 +4473,9 @@ enum sctp_disposition sctp_sf_discard_chunk(struct net *net, + { + 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. +-- +2.33.0 + diff --git a/queue-5.10/sctp-use-init_tag-from-inithdr-for-abort-chunk.patch b/queue-5.10/sctp-use-init_tag-from-inithdr-for-abort-chunk.patch new file mode 100644 index 00000000000..538469435de --- /dev/null +++ b/queue-5.10/sctp-use-init_tag-from-inithdr-for-abort-chunk.patch @@ -0,0 +1,42 @@ +From 115fd3cae40afa55c75c6ebf5041151f567ff70d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Oct 2021 07:42:41 -0400 +Subject: sctp: use init_tag from inithdr for ABORT chunk + +From: Xin Long + +[ Upstream commit 4f7019c7eb33967eb87766e0e4602b5576873680 ] + +Currently Linux SCTP uses the verification tag of the existing SCTP +asoc when failing to process and sending the packet with the ABORT +chunk. This will result in the peer accepting the ABORT chunk and +removing the SCTP asoc. One could exploit this to terminate a SCTP +asoc. + +This patch is to fix it by always using the initiate tag of the +received INIT chunk for the ABORT chunk to be sent. + +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: Sasha Levin +--- + net/sctp/sm_statefuns.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index b65bdaa84228..89a86728184d 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -6248,6 +6248,7 @@ static struct sctp_packet *sctp_ootb_pkt_new( + * yet. + */ + switch (chunk->chunk_hdr->type) { ++ case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + { + struct sctp_initack_chunk *initack; +-- +2.33.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 8a39ad56603..29a25c67c09 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -63,3 +63,10 @@ phy-phy_ethtool_ksettings_get-lock-the-phy-for-consistency.patch phy-phy_ethtool_ksettings_set-move-after-phy_start_aneg.patch phy-phy_start_aneg-add-an-unlocked-version.patch phy-phy_ethtool_ksettings_set-lock-the-phy-while-changing-settings.patch +sctp-use-init_tag-from-inithdr-for-abort-chunk.patch +sctp-fix-the-processing-for-init_ack-chunk.patch +sctp-fix-the-processing-for-cookie_echo-chunk.patch +sctp-add-vtag-check-in-sctp_sf_violation.patch +sctp-add-vtag-check-in-sctp_sf_do_8_5_1_e_sa.patch +sctp-add-vtag-check-in-sctp_sf_ootb.patch +lan743x-fix-endianness-when-accessing-descriptors.patch