Takashi Iwai 9dcbb3
From d8861bab48b6c1fc3cdbcab8ff9d1eaea43afe7f Mon Sep 17 00:00:00 2001
Takashi Iwai 9dcbb3
From: Michael Braun <michael-dev@fami-braun.de>
Takashi Iwai 9dcbb3
Date: Thu, 4 Mar 2021 20:52:52 +0100
Takashi Iwai 9dcbb3
Subject: [PATCH] gianfar: fix jumbo packets+napi+rx overrun crash
Takashi Iwai 9dcbb3
Git-commit: d8861bab48b6c1fc3cdbcab8ff9d1eaea43afe7f
Takashi Iwai 9dcbb3
Patch-mainline: v5.12-rc3
Takashi Iwai 9dcbb3
References: CVE-2021-29264 bsc#1184168
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
[ backport note: dropped the first chunk in the original patch as the
Takashi Iwai 9dcbb3
  old kernel code already has the size check -- tiwai ]
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
When using jumbo packets and overrunning rx queue with napi enabled,
Takashi Iwai 9dcbb3
the following sequence is observed in gfar_add_rx_frag:
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
   | lstatus                              |       | skb                   |
Takashi Iwai 9dcbb3
t  | lstatus,  size, flags                | first | len, data_len, *ptr   |
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
---+--------------------------------------+-------+-----------------------+
Takashi Iwai 9dcbb3
13 | 18002348, 9032, INTERRUPT LAST       | 0     | 9600, 8000,  f554c12e |
Takashi Iwai 9dcbb3
12 | 10000640, 1600, INTERRUPT            | 0     | 8000, 6400,  f554c12e |
Takashi Iwai 9dcbb3
11 | 10000640, 1600, INTERRUPT            | 0     | 6400, 4800,  f554c12e |
Takashi Iwai 9dcbb3
10 | 10000640, 1600, INTERRUPT            | 0     | 4800, 3200,  f554c12e |
Takashi Iwai 9dcbb3
09 | 10000640, 1600, INTERRUPT            | 0     | 3200, 1600,  f554c12e |
Takashi Iwai 9dcbb3
08 | 14000640, 1600, INTERRUPT FIRST      | 0     | 1600, 0,     f554c12e |
Takashi Iwai 9dcbb3
07 | 14000640, 1600, INTERRUPT FIRST      | 1     | 0,    0,     f554c12e |
Takashi Iwai 9dcbb3
06 | 1c000080, 128,  INTERRUPT LAST FIRST | 1     | 0,    0,     abf3bd6e |
Takashi Iwai 9dcbb3
05 | 18002348, 9032, INTERRUPT LAST       | 0     | 8000, 6400,  c5a57780 |
Takashi Iwai 9dcbb3
04 | 10000640, 1600, INTERRUPT            | 0     | 6400, 4800,  c5a57780 |
Takashi Iwai 9dcbb3
03 | 10000640, 1600, INTERRUPT            | 0     | 4800, 3200,  c5a57780 |
Takashi Iwai 9dcbb3
02 | 10000640, 1600, INTERRUPT            | 0     | 3200, 1600,  c5a57780 |
Takashi Iwai 9dcbb3
01 | 10000640, 1600, INTERRUPT            | 0     | 1600, 0,     c5a57780 |
Takashi Iwai 9dcbb3
00 | 14000640, 1600, INTERRUPT FIRST      | 1     | 0,    0,     c5a57780 |
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
So at t=7 a new packets is started but not finished, probably due to rx
Takashi Iwai 9dcbb3
overrun - but rx overrun is not indicated in the flags. Instead a new
Takashi Iwai 9dcbb3
packets starts at t=8. This results in skb->len to exceed size for the LAST
Takashi Iwai 9dcbb3
fragment at t=13 and thus a negative fragment size added to the skb.
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
This then crashes:
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
kernel BUG at include/linux/skbuff.h:2277!
Takashi Iwai 9dcbb3
Oops: Exception in kernel mode, sig: 5 [#1]
Takashi Iwai 9dcbb3
...
Takashi Iwai 9dcbb3
NIP [c04689f4] skb_pull+0x2c/0x48
Takashi Iwai 9dcbb3
LR [c03f62ac] gfar_clean_rx_ring+0x2e4/0x844
Takashi Iwai 9dcbb3
Call Trace:
Takashi Iwai 9dcbb3
[ec4bfd38] [c06a84c4] _raw_spin_unlock_irqrestore+0x60/0x7c (unreliable)
Takashi Iwai 9dcbb3
[ec4bfda8] [c03f6a44] gfar_poll_rx_sq+0x48/0xe4
Takashi Iwai 9dcbb3
[ec4bfdc8] [c048d504] __napi_poll+0x54/0x26c
Takashi Iwai 9dcbb3
[ec4bfdf8] [c048d908] net_rx_action+0x138/0x2c0
Takashi Iwai 9dcbb3
[ec4bfe68] [c06a8f34] __do_softirq+0x3a4/0x4fc
Takashi Iwai 9dcbb3
[ec4bfed8] [c0040150] run_ksoftirqd+0x58/0x70
Takashi Iwai 9dcbb3
[ec4bfee8] [c0066ecc] smpboot_thread_fn+0x184/0x1cc
Takashi Iwai 9dcbb3
[ec4bff08] [c0062718] kthread+0x140/0x144
Takashi Iwai 9dcbb3
[ec4bff38] [c0012350] ret_from_kernel_thread+0x14/0x1c
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
This patch fixes this by checking for computed LAST fragment size, so a
Takashi Iwai 9dcbb3
negative sized fragment is never added.
Takashi Iwai 9dcbb3
In order to prevent the newer rx frame from getting corrupted, the FIRST
Takashi Iwai 9dcbb3
flag is checked to discard the incomplete older frame.
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
Takashi Iwai 9dcbb3
Signed-off-by: David S. Miller <davem@davemloft.net>
Takashi Iwai 9dcbb3
---
Takashi Iwai 9dcbb3
 drivers/net/ethernet/freescale/gianfar.c |   11 +++++++++++
Takashi Iwai 9dcbb3
 1 file changed, 11 insertions(+)
Takashi Iwai 9dcbb3
Takashi Iwai 9dcbb3
--- a/drivers/net/ethernet/freescale/gianfar.c
Takashi Iwai 9dcbb3
+++ b/drivers/net/ethernet/freescale/gianfar.c
Takashi Iwai 9dcbb3
@@ -3107,6 +3107,17 @@ int gfar_clean_rx_ring(struct gfar_priv_
Takashi Iwai 9dcbb3
 		if (lstatus & BD_LFLAG(RXBD_EMPTY))
Takashi Iwai 9dcbb3
 			break;
Takashi Iwai 9dcbb3
 
Takashi Iwai 9dcbb3
+		/* lost RXBD_LAST descriptor due to overrun */
Takashi Iwai 9dcbb3
+		if (skb &&
Takashi Iwai 9dcbb3
+		    (lstatus & BD_LFLAG(RXBD_FIRST))) {
Takashi Iwai 9dcbb3
+			/* discard faulty buffer */
Takashi Iwai 9dcbb3
+			dev_kfree_skb(skb);
Takashi Iwai 9dcbb3
+			skb = NULL;
Takashi Iwai 9dcbb3
+			rx_queue->stats.rx_dropped++;
Takashi Iwai 9dcbb3
+
Takashi Iwai 9dcbb3
+			/* can continue normally */
Takashi Iwai 9dcbb3
+		}
Takashi Iwai 9dcbb3
+
Takashi Iwai 9dcbb3
 		/* order rx buffer descriptor reads */
Takashi Iwai 9dcbb3
 		rmb();
Takashi Iwai 9dcbb3