From b173ae66c90e30d044f395d761e91d871d15b339 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 24 Jan 2022 16:59:48 +0100 Subject: [PATCH] 4.9-stable patches added patches: gianfar-fix-jumbo-packets-napi-rx-overrun-crash.patch gianfar-simplify-fcs-handling-and-fix-memory-leak.patch --- ...-jumbo-packets-napi-rx-overrun-crash.patch | 97 +++++++++++++++++++ ...ify-fcs-handling-and-fix-memory-leak.patch | 73 ++++++++++++++ queue-4.9/series | 2 + 3 files changed, 172 insertions(+) create mode 100644 queue-4.9/gianfar-fix-jumbo-packets-napi-rx-overrun-crash.patch create mode 100644 queue-4.9/gianfar-simplify-fcs-handling-and-fix-memory-leak.patch diff --git a/queue-4.9/gianfar-fix-jumbo-packets-napi-rx-overrun-crash.patch b/queue-4.9/gianfar-fix-jumbo-packets-napi-rx-overrun-crash.patch new file mode 100644 index 00000000000..1a87fa97c17 --- /dev/null +++ b/queue-4.9/gianfar-fix-jumbo-packets-napi-rx-overrun-crash.patch @@ -0,0 +1,97 @@ +From d8861bab48b6c1fc3cdbcab8ff9d1eaea43afe7f Mon Sep 17 00:00:00 2001 +From: Michael Braun +Date: Thu, 4 Mar 2021 20:52:52 +0100 +Subject: gianfar: fix jumbo packets+napi+rx overrun crash + +From: Michael Braun + +commit d8861bab48b6c1fc3cdbcab8ff9d1eaea43afe7f upstream. + +When using jumbo packets and overrunning rx queue with napi enabled, +the following sequence is observed in gfar_add_rx_frag: + + | lstatus | | skb | +t | lstatus, size, flags | first | len, data_len, *ptr | +---+--------------------------------------+-------+-----------------------+ +13 | 18002348, 9032, INTERRUPT LAST | 0 | 9600, 8000, f554c12e | +12 | 10000640, 1600, INTERRUPT | 0 | 8000, 6400, f554c12e | +11 | 10000640, 1600, INTERRUPT | 0 | 6400, 4800, f554c12e | +10 | 10000640, 1600, INTERRUPT | 0 | 4800, 3200, f554c12e | +09 | 10000640, 1600, INTERRUPT | 0 | 3200, 1600, f554c12e | +08 | 14000640, 1600, INTERRUPT FIRST | 0 | 1600, 0, f554c12e | +07 | 14000640, 1600, INTERRUPT FIRST | 1 | 0, 0, f554c12e | +06 | 1c000080, 128, INTERRUPT LAST FIRST | 1 | 0, 0, abf3bd6e | +05 | 18002348, 9032, INTERRUPT LAST | 0 | 8000, 6400, c5a57780 | +04 | 10000640, 1600, INTERRUPT | 0 | 6400, 4800, c5a57780 | +03 | 10000640, 1600, INTERRUPT | 0 | 4800, 3200, c5a57780 | +02 | 10000640, 1600, INTERRUPT | 0 | 3200, 1600, c5a57780 | +01 | 10000640, 1600, INTERRUPT | 0 | 1600, 0, c5a57780 | +00 | 14000640, 1600, INTERRUPT FIRST | 1 | 0, 0, c5a57780 | + +So at t=7 a new packets is started but not finished, probably due to rx +overrun - but rx overrun is not indicated in the flags. Instead a new +packets starts at t=8. This results in skb->len to exceed size for the LAST +fragment at t=13 and thus a negative fragment size added to the skb. + +This then crashes: + +kernel BUG at include/linux/skbuff.h:2277! +Oops: Exception in kernel mode, sig: 5 [#1] +... +NIP [c04689f4] skb_pull+0x2c/0x48 +LR [c03f62ac] gfar_clean_rx_ring+0x2e4/0x844 +Call Trace: +[ec4bfd38] [c06a84c4] _raw_spin_unlock_irqrestore+0x60/0x7c (unreliable) +[ec4bfda8] [c03f6a44] gfar_poll_rx_sq+0x48/0xe4 +[ec4bfdc8] [c048d504] __napi_poll+0x54/0x26c +[ec4bfdf8] [c048d908] net_rx_action+0x138/0x2c0 +[ec4bfe68] [c06a8f34] __do_softirq+0x3a4/0x4fc +[ec4bfed8] [c0040150] run_ksoftirqd+0x58/0x70 +[ec4bfee8] [c0066ecc] smpboot_thread_fn+0x184/0x1cc +[ec4bff08] [c0062718] kthread+0x140/0x144 +[ec4bff38] [c0012350] ret_from_kernel_thread+0x14/0x1c + +This patch fixes this by checking for computed LAST fragment size, so a +negative sized fragment is never added. +In order to prevent the newer rx frame from getting corrupted, the FIRST +flag is checked to discard the incomplete older frame. + +Signed-off-by: Michael Braun +Signed-off-by: David S. Miller +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/freescale/gianfar.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/net/ethernet/freescale/gianfar.c ++++ b/drivers/net/ethernet/freescale/gianfar.c +@@ -2947,6 +2947,10 @@ static bool gfar_add_rx_frag(struct gfar + if (lstatus & BD_LFLAG(RXBD_LAST)) + size -= skb->len; + ++ WARN(size < 0, "gianfar: rx fragment size underflow"); ++ if (size < 0) ++ return false; ++ + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + rxb->page_offset + RXBUF_ALIGNMENT, + size, GFAR_RXB_TRUESIZE); +@@ -3108,6 +3112,17 @@ int gfar_clean_rx_ring(struct gfar_priv_ + if (lstatus & BD_LFLAG(RXBD_EMPTY)) + break; + ++ /* lost RXBD_LAST descriptor due to overrun */ ++ if (skb && ++ (lstatus & BD_LFLAG(RXBD_FIRST))) { ++ /* discard faulty buffer */ ++ dev_kfree_skb(skb); ++ skb = NULL; ++ rx_queue->stats.rx_dropped++; ++ ++ /* can continue normally */ ++ } ++ + /* order rx buffer descriptor reads */ + rmb(); + diff --git a/queue-4.9/gianfar-simplify-fcs-handling-and-fix-memory-leak.patch b/queue-4.9/gianfar-simplify-fcs-handling-and-fix-memory-leak.patch new file mode 100644 index 00000000000..bfae92e7d86 --- /dev/null +++ b/queue-4.9/gianfar-simplify-fcs-handling-and-fix-memory-leak.patch @@ -0,0 +1,73 @@ +From d903ec77118c09f93a610b384d83a6df33a64fe6 Mon Sep 17 00:00:00 2001 +From: Andy Spencer +Date: Thu, 22 Feb 2018 11:05:33 -0800 +Subject: gianfar: simplify FCS handling and fix memory leak + +From: Andy Spencer + +commit d903ec77118c09f93a610b384d83a6df33a64fe6 upstream. + +Previously, buffer descriptors containing only the frame check sequence +(FCS) were skipped and not added to the skb. However, the page reference +count was still incremented, leading to a memory leak. + +Fixing this inside gfar_add_rx_frag() is difficult due to reserved +memory handling and page reuse. Instead, move the FCS handling to +gfar_process_frame() and trim off the FCS before passing the skb up the +networking stack. + +Signed-off-by: Andy Spencer +Signed-off-by: Jim Gruen +Signed-off-by: David S. Miller +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/freescale/gianfar.c | 23 +++++++---------------- + 1 file changed, 7 insertions(+), 16 deletions(-) + +--- a/drivers/net/ethernet/freescale/gianfar.c ++++ b/drivers/net/ethernet/freescale/gianfar.c +@@ -2939,29 +2939,17 @@ static bool gfar_add_rx_frag(struct gfar + { + int size = lstatus & BD_LENGTH_MASK; + struct page *page = rxb->page; +- bool last = !!(lstatus & BD_LFLAG(RXBD_LAST)); +- +- /* Remove the FCS from the packet length */ +- if (last) +- size -= ETH_FCS_LEN; + + if (likely(first)) { + skb_put(skb, size); + } else { + /* the last fragments' length contains the full frame length */ +- if (last) ++ if (lstatus & BD_LFLAG(RXBD_LAST)) + size -= skb->len; + +- /* Add the last fragment if it contains something other than +- * the FCS, otherwise drop it and trim off any part of the FCS +- * that was already received. +- */ +- if (size > 0) +- skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, +- rxb->page_offset + RXBUF_ALIGNMENT, +- size, GFAR_RXB_TRUESIZE); +- else if (size < 0) +- pskb_trim(skb, skb->len + size); ++ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, ++ rxb->page_offset + RXBUF_ALIGNMENT, ++ size, GFAR_RXB_TRUESIZE); + } + + /* try reuse page */ +@@ -3074,6 +3062,9 @@ static void gfar_process_frame(struct ne + if (priv->padding) + skb_pull(skb, priv->padding); + ++ /* Trim off the FCS */ ++ pskb_trim(skb, skb->len - ETH_FCS_LEN); ++ + if (ndev->features & NETIF_F_RXCSUM) + gfar_rx_checksum(skb, fcb); + diff --git a/queue-4.9/series b/queue-4.9/series index f0d31b5f875..a845b740e4f 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -146,3 +146,5 @@ lib82596-fix-irq-check-in-sni_82596_probe.patch revert-gup-document-and-work-around-cow-can-break-either-way-issue.patch gup-document-and-work-around-cow-can-break-either-way-issue.patch drm-ttm-nouveau-don-t-call-tt-destroy-callback-on-alloc-failure.patch +gianfar-simplify-fcs-handling-and-fix-memory-leak.patch +gianfar-fix-jumbo-packets-napi-rx-overrun-crash.patch -- 2.47.2