]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Jun 2024 11:35:11 +0000 (13:35 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Jun 2024 11:35:11 +0000 (13:35 +0200)
added patches:
net-ena-fix-dma-syncing-in-xdp-path-when-swiotlb-is-on.patch

queue-5.15/net-ena-fix-dma-syncing-in-xdp-path-when-swiotlb-is-on.patch [new file with mode: 0644]
queue-5.15/series

diff --git a/queue-5.15/net-ena-fix-dma-syncing-in-xdp-path-when-swiotlb-is-on.patch b/queue-5.15/net-ena-fix-dma-syncing-in-xdp-path-when-swiotlb-is-on.patch
new file mode 100644 (file)
index 0000000..7e797ef
--- /dev/null
@@ -0,0 +1,177 @@
+From d760117060cf2e90b5c59c5492cab179a4dbce01 Mon Sep 17 00:00:00 2001
+From: David Arinzon <darinzon@amazon.com>
+Date: Mon, 11 Dec 2023 06:28:00 +0000
+Subject: net: ena: Fix DMA syncing in XDP path when SWIOTLB is on
+
+From: David Arinzon <darinzon@amazon.com>
+
+commit d760117060cf2e90b5c59c5492cab179a4dbce01 upstream.
+
+This patch fixes two issues:
+
+Issue 1
+-------
+Description
+```````````
+Current code does not call dma_sync_single_for_cpu() to sync data from
+the device side memory to the CPU side memory before the XDP code path
+uses the CPU side data.
+This causes the XDP code path to read the unset garbage data in the CPU
+side memory, resulting in incorrect handling of the packet by XDP.
+
+Solution
+````````
+1. Add a call to dma_sync_single_for_cpu() before the XDP code starts to
+   use the data in the CPU side memory.
+2. The XDP code verdict can be XDP_PASS, in which case there is a
+   fallback to the non-XDP code, which also calls
+   dma_sync_single_for_cpu().
+   To avoid calling dma_sync_single_for_cpu() twice:
+2.1. Put the dma_sync_single_for_cpu() in the code in such a place where
+     it happens before XDP and non-XDP code.
+2.2. Remove the calls to dma_sync_single_for_cpu() in the non-XDP code
+     for the first buffer only (rx_copybreak and non-rx_copybreak
+     cases), since the new call that was added covers these cases.
+     The call to dma_sync_single_for_cpu() for the second buffer and on
+     stays because only the first buffer is handled by the newly added
+     dma_sync_single_for_cpu(). And there is no need for special
+     handling of the second buffer and on for the XDP path since
+     currently the driver supports only single buffer packets.
+
+Issue 2
+-------
+Description
+```````````
+In case the XDP code forwarded the packet (ENA_XDP_FORWARDED),
+ena_unmap_rx_buff_attrs() is called with attrs set to 0.
+This means that before unmapping the buffer, the internal function
+dma_unmap_page_attrs() will also call dma_sync_single_for_cpu() on
+the whole buffer (not only on the data part of it).
+This sync is both wasteful (since a sync was already explicitly
+called before) and also causes a bug, which will be explained
+using the below diagram.
+
+The following diagram shows the flow of events causing the bug.
+The order of events is (1)-(4) as shown in the diagram.
+
+CPU side memory area
+
+     (3)convert_to_xdp_frame() initializes the
+        headroom with xdpf metadata
+                      ||
+                      \/
+          ___________________________________
+         |                                   |
+ 0       |                                   V                       4K
+ ---------------------------------------------------------------------
+ | xdpf->data      | other xdpf       |   < data >   | tailroom ||...|
+ |                 | fields           |              | GARBAGE  ||   |
+ ---------------------------------------------------------------------
+
+                   /\                        /\
+                   ||                        ||
+   (4)ena_unmap_rx_buff_attrs() calls     (2)dma_sync_single_for_cpu()
+      dma_sync_single_for_cpu() on the       copies data from device
+      whole buffer page, overwriting         side to CPU side memory
+      the xdpf->data with GARBAGE.           ||
+ 0                                                                   4K
+ ---------------------------------------------------------------------
+ | headroom                           |   < data >   | tailroom ||...|
+ | GARBAGE                            |              | GARBAGE  ||   |
+ ---------------------------------------------------------------------
+
+Device side memory area                      /\
+                                             ||
+                               (1) device writes RX packet data
+
+After the call to ena_unmap_rx_buff_attrs() in (4), the xdpf->data
+becomes corrupted, and so when it is later accessed in
+ena_clean_xdp_irq()->xdp_return_frame(), it causes a page fault,
+crashing the kernel.
+
+Solution
+````````
+Explicitly tell ena_unmap_rx_buff_attrs() not to call
+dma_sync_single_for_cpu() by passing it the ENA_DMA_ATTR_SKIP_CPU_SYNC
+flag.
+
+Fixes: f7d625adeb7b ("net: ena: Add dynamic recycling mechanism for rx buffers")
+Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
+Signed-off-by: David Arinzon <darinzon@amazon.com>
+Link: https://lore.kernel.org/r/20231211062801.27891-4-darinzon@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/amazon/ena/ena_netdev.c |   23 +++++++++--------------
+ 1 file changed, 9 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
++++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
+@@ -1495,11 +1495,6 @@ static struct sk_buff *ena_rx_skb(struct
+               if (unlikely(!skb))
+                       return NULL;
+-              /* sync this buffer for CPU use */
+-              dma_sync_single_for_cpu(rx_ring->dev,
+-                                      dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
+-                                      len,
+-                                      DMA_FROM_DEVICE);
+               skb_copy_to_linear_data(skb, buf_addr + buf_offset, len);
+               dma_sync_single_for_device(rx_ring->dev,
+                                          dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
+@@ -1518,17 +1513,10 @@ static struct sk_buff *ena_rx_skb(struct
+       buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom);
+-      pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr);
+-
+       /* If XDP isn't loaded try to reuse part of the RX buffer */
+       reuse_rx_buf_page = !is_xdp_loaded &&
+                           ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
+-      dma_sync_single_for_cpu(rx_ring->dev,
+-                              pre_reuse_paddr + pkt_offset,
+-                              len,
+-                              DMA_FROM_DEVICE);
+-
+       if (!reuse_rx_buf_page)
+               ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);
+@@ -1724,6 +1712,7 @@ static int ena_clean_rx_irq(struct ena_r
+       int xdp_flags = 0;
+       int total_len = 0;
+       int xdp_verdict;
++      u8 pkt_offset;
+       int rc = 0;
+       int i;
+@@ -1750,13 +1739,19 @@ static int ena_clean_rx_irq(struct ena_r
+               /* First descriptor might have an offset set by the device */
+               rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id];
+-              rx_info->buf_offset += ena_rx_ctx.pkt_offset;
++              pkt_offset = ena_rx_ctx.pkt_offset;
++              rx_info->buf_offset += pkt_offset;
+               netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
+                         "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n",
+                         rx_ring->qid, ena_rx_ctx.descs, ena_rx_ctx.l3_proto,
+                         ena_rx_ctx.l4_proto, ena_rx_ctx.hash);
++              dma_sync_single_for_cpu(rx_ring->dev,
++                                      dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset,
++                                      rx_ring->ena_bufs[0].len,
++                                      DMA_FROM_DEVICE);
++
+               if (ena_xdp_present_ring(rx_ring))
+                       xdp_verdict = ena_xdp_handle_buff(rx_ring, &xdp, ena_rx_ctx.descs);
+@@ -1782,7 +1777,7 @@ static int ena_clean_rx_irq(struct ena_r
+                               if (xdp_verdict & ENA_XDP_FORWARDED) {
+                                       ena_unmap_rx_buff_attrs(rx_ring,
+                                                               &rx_ring->rx_buffer_info[req_id],
+-                                                              0);
++                                                              DMA_ATTR_SKIP_CPU_SYNC);
+                                       rx_ring->rx_buffer_info[req_id].page = NULL;
+                               }
+                       }
index 0f9c3e9557a8ad0379e184aa8fcc3e0facc3502f..d7cdc7e03999c612f9f0e99849d3c06afe9865f0 100644 (file)
@@ -334,3 +334,4 @@ hwmon-shtc1-fix-property-misspelling.patch
 alsa-timer-set-lower-bound-of-start-tick-time.patch
 kvm-x86-don-t-advertise-guest.maxphyaddr-as-host.maxphyaddr-in-cpuid.patch
 genirq-cpuhotplug-x86-vector-prevent-vector-leak-during-cpu-offline.patch
+net-ena-fix-dma-syncing-in-xdp-path-when-swiotlb-is-on.patch