Blame SOURCES/CVE-2022-2964.patch

6e64c9
From f199e966e1da09385b3a822b60220c3e7dad5d15 Mon Sep 17 00:00:00 2001
6e64c9
From: Yannick Cote <ycote@redhat.com>
6e64c9
Date: Wed, 7 Dec 2022 13:51:50 -0500
6e64c9
Subject: [KPATCH CVE-2022-2964] kpatch fixes for CVE-2022-2964
6e64c9
6e64c9
Kernels:
6e64c9
4.18.0-425.3.1.el8
6e64c9
6e64c9
6e64c9
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-8/-/merge_requests/65
6e64c9
Approved-by: Joe Lawrence (@joe.lawrence)
6e64c9
Changes since last build:
6e64c9
arches: x86_64 ppc64le
6e64c9
ax88179_178a.o: changed function: ax88179_rx_fixup
6e64c9
---------------------------
6e64c9
6e64c9
Modifications: none
6e64c9
6e64c9
commit f12daa92e8162af22fa80f7a69c2b7069a600f24
6e64c9
Author: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
6e64c9
Date:   Wed Nov 23 17:38:38 2022 +0100
6e64c9
6e64c9
    net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
6e64c9
6e64c9
    Bugzilla: https://bugzilla.redhat.com/2142724
6e64c9
    CVE: CVE-2022-2964
6e64c9
6e64c9
    commit 57bc3d3ae8c14df3ceb4e17d26ddf9eeab304581
6e64c9
    Author: Jann Horn <jannh@google.com>
6e64c9
    Date:   Wed Jan 26 14:14:52 2022 +0100
6e64c9
6e64c9
        net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup
6e64c9
6e64c9
        ax88179_rx_fixup() contains several out-of-bounds accesses that can be
6e64c9
        triggered by a malicious (or defective) USB device, in particular:
6e64c9
6e64c9
         - The metadata array (hdr_off..hdr_off+2*pkt_cnt) can be out of bounds,
6e64c9
           causing OOB reads and (on big-endian systems) OOB endianness flips.
6e64c9
         - A packet can overlap the metadata array, causing a later OOB
6e64c9
           endianness flip to corrupt data used by a cloned SKB that has already
6e64c9
           been handed off into the network stack.
6e64c9
         - A packet SKB can be constructed whose tail is far beyond its end,
6e64c9
           causing out-of-bounds heap data to be considered part of the SKB's
6e64c9
           data.
6e64c9
6e64c9
        I have tested that this can be used by a malicious USB device to send a
6e64c9
        bogus ICMPv6 Echo Request and receive an ICMPv6 Echo Reply in response
6e64c9
        that contains random kernel heap data.
6e64c9
        It's probably also possible to get OOB writes from this on a
6e64c9
        little-endian system somehow - maybe by triggering skb_cow() via IP
6e64c9
        options processing -, but I haven't tested that.
6e64c9
6e64c9
        Fixes: e2ca90c276e1 ("ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver")
6e64c9
        Cc: stable@kernel.org
6e64c9
        Signed-off-by: Jann Horn <jannh@google.com>
6e64c9
        Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
6e64c9
6e64c9
    Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
6e64c9
6e64c9
commit 065aec7252fd7a895103db717faf36984cd3ce35
6e64c9
Author: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
6e64c9
Date:   Wed Nov 23 17:38:39 2022 +0100
6e64c9
6e64c9
    net: usb: ax88179_178a: Fix packet receiving
6e64c9
6e64c9
    Bugzilla: https://bugzilla.redhat.com/2142724
6e64c9
    CVE: CVE-2022-2964
6e64c9
6e64c9
    commit f8ebb3ac881b17712e1d5967c97ab1806b16d3d6
6e64c9
    Author: Jose Alonso <joalonsof@gmail.com>
6e64c9
    Date:   Tue Jun 28 12:13:02 2022 -0300
6e64c9
6e64c9
        net: usb: ax88179_178a: Fix packet receiving
6e64c9
6e64c9
        This patch corrects packet receiving in ax88179_rx_fixup.
6e64c9
6e64c9
        - problem observed:
6e64c9
          ifconfig shows allways a lot of 'RX Errors' while packets
6e64c9
          are received normally.
6e64c9
6e64c9
          This occurs because ax88179_rx_fixup does not recognise properly
6e64c9
          the usb urb received.
6e64c9
          The packets are normally processed and at the end, the code exits
6e64c9
          with 'return 0', generating RX Errors.
6e64c9
          (pkt_cnt==-2 and ptk_hdr over field rx_hdr trying to identify
6e64c9
           another packet there)
6e64c9
6e64c9
          This is a usb urb received by "tcpdump -i usbmon2 -X" on a
6e64c9
          little-endian CPU:
6e64c9
          0x0000:  eeee f8e3 3b19 87a0 94de 80e3 daac 0800
6e64c9
                   ^         packet 1 start (pkt_len = 0x05ec)
6e64c9
                   ^^^^      IP alignment pseudo header
6e64c9
                        ^    ethernet packet start
6e64c9
                   last byte ethernet packet   v
6e64c9
                   padding (8-bytes aligned)     vvvv vvvv
6e64c9
          0x05e0:  c92d d444 1420 8a69 83dd 272f e82b 9811
6e64c9
          0x05f0:  eeee f8e3 3b19 87a0 94de 80e3 daac 0800
6e64c9
          ...      ^ packet 2
6e64c9
          0x0be0:  eeee f8e3 3b19 87a0 94de 80e3 daac 0800
6e64c9
          ...
6e64c9
          0x1130:  9d41 9171 8a38 0ec5 eeee f8e3 3b19 87a0
6e64c9
          ...
6e64c9
          0x1720:  8cfc 15ff 5e4c e85c eeee f8e3 3b19 87a0
6e64c9
          ...
6e64c9
          0x1d10:  ecfa 2a3a 19ab c78c eeee f8e3 3b19 87a0
6e64c9
          ...
6e64c9
          0x2070:  eeee f8e3 3b19 87a0 94de 80e3 daac 0800
6e64c9
          ...      ^ packet 7
6e64c9
          0x2120:  7c88 4ca5 5c57 7dcc 0d34 7577 f778 7e0a
6e64c9
          0x2130:  f032 e093 7489 0740 3008 ec05 0000 0080
6e64c9
                                       ====1==== ====2====
6e64c9
                   hdr_off             ^
6e64c9
                   pkt_len = 0x05ec         ^^^^
6e64c9
                   AX_RXHDR_*=0x00830  ^^^^   ^
6e64c9
                   pkt_len = 0                        ^^^^
6e64c9
                   AX_RXHDR_DROP_ERR=0x80000000  ^^^^   ^
6e64c9
          0x2140:  3008 ec05 0000 0080 3008 5805 0000 0080
6e64c9
          0x2150:  3008 ec05 0000 0080 3008 ec05 0000 0080
6e64c9
          0x2160:  3008 5803 0000 0080 3008 c800 0000 0080
6e64c9
                   ===11==== ===12==== ===13==== ===14====
6e64c9
          0x2170:  0000 0000 0e00 3821
6e64c9
                             ^^^^ ^^^^ rx_hdr
6e64c9
                             ^^^^      pkt_cnt=14
6e64c9
                                  ^^^^ hdr_off=0x2138
6e64c9
                   ^^^^ ^^^^           padding
6e64c9
6e64c9
          The dump shows that pkt_cnt is the number of entrys in the
6e64c9
          per-packet metadata. It is "2 * packet count".
6e64c9
          Each packet have two entrys. The first have a valid
6e64c9
          value (pkt_len and AX_RXHDR_*) and the second have a
6e64c9
          dummy-header 0x80000000 (pkt_len=0 with AX_RXHDR_DROP_ERR).
6e64c9
          Why exists dummy-header for each packet?!?
6e64c9
          My guess is that this was done probably to align the
6e64c9
          entry for each packet to 64-bits and maintain compatibility
6e64c9
          with old firmware.
6e64c9
          There is also a padding (0x00000000) before the rx_hdr to
6e64c9
          align the end of rx_hdr to 64-bit.
6e64c9
          Note that packets have a alignment of 64-bits (8-bytes).
6e64c9
6e64c9
          This patch assumes that the dummy-header and the last
6e64c9
          padding are optional. So it preserves semantics and
6e64c9
          recognises the same valid packets as the current code.
6e64c9
6e64c9
          This patch was made using only the dumpfile information and
6e64c9
          tested with only one device:
6e64c9
          0b95:1790 ASIX Electronics Corp. AX88179 Gigabit Ethernet
6e64c9
6e64c9
        Fixes: 57bc3d3ae8c1 ("net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup")
6e64c9
        Fixes: e2ca90c276e1 ("ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver")
6e64c9
        Signed-off-by: Jose Alonso <joalonsof@gmail.com>
6e64c9
        Acked-by: Paolo Abeni <pabeni@redhat.com>
6e64c9
        Link: https://lore.kernel.org/r/d6970bb04bf67598af4d316eaeb1792040b18cfd.camel@gmail.com
6e64c9
        Signed-off-by: Paolo Abeni <pabeni@redhat.com>
6e64c9
6e64c9
    Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
6e64c9
6e64c9
Signed-off-by: Yannick Cote <ycote@redhat.com>
6e64c9
---
6e64c9
 drivers/net/usb/ax88179_178a.c | 113 +++++++++++++++++++++++++--------
6e64c9
 1 file changed, 87 insertions(+), 26 deletions(-)
6e64c9
6e64c9
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
6e64c9
index 2eb02808812c..a4896f396c7c 100644
6e64c9
--- a/drivers/net/usb/ax88179_178a.c
6e64c9
+++ b/drivers/net/usb/ax88179_178a.c
6e64c9
@@ -1477,58 +1477,119 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
6e64c9
 	u16 hdr_off;
6e64c9
 	u32 *pkt_hdr;
6e64c9
 
6e64c9
-	/* This check is no longer done by usbnet */
6e64c9
-	if (skb->len < dev->net->hard_header_len)
6e64c9
+	/* At the end of the SKB, there's a header telling us how many packets
6e64c9
+	 * are bundled into this buffer and where we can find an array of
6e64c9
+	 * per-packet metadata (which contains elements encoded into u16).
6e64c9
+	 */
6e64c9
+
6e64c9
+	/* SKB contents for current firmware:
6e64c9
+	 *   <packet 1> <padding>
6e64c9
+	 *   ...
6e64c9
+	 *   <packet N> <padding>
6e64c9
+	 *   <per-packet metadata entry 1> <dummy header>
6e64c9
+	 *   ...
6e64c9
+	 *   <per-packet metadata entry N> <dummy header>
6e64c9
+	 *   <padding2> <rx_hdr>
6e64c9
+	 *
6e64c9
+	 * where:
6e64c9
+	 *   <packet N> contains pkt_len bytes:
6e64c9
+	 *		2 bytes of IP alignment pseudo header
6e64c9
+	 *		packet received
6e64c9
+	 *   <per-packet metadata entry N> contains 4 bytes:
6e64c9
+	 *		pkt_len and fields AX_RXHDR_*
6e64c9
+	 *   <padding>	0-7 bytes to terminate at
6e64c9
+	 *		8 bytes boundary (64-bit).
6e64c9
+	 *   <padding2> 4 bytes to make rx_hdr terminate at
6e64c9
+	 *		8 bytes boundary (64-bit)
6e64c9
+	 *   <dummy-header> contains 4 bytes:
6e64c9
+	 *		pkt_len=0 and AX_RXHDR_DROP_ERR
6e64c9
+	 *   <rx-hdr>	contains 4 bytes:
6e64c9
+	 *		pkt_cnt and hdr_off (offset of
6e64c9
+	 *		  <per-packet metadata entry 1>)
6e64c9
+	 *
6e64c9
+	 * pkt_cnt is number of entrys in the per-packet metadata.
6e64c9
+	 * In current firmware there is 2 entrys per packet.
6e64c9
+	 * The first points to the packet and the
6e64c9
+	 *  second is a dummy header.
6e64c9
+	 * This was done probably to align fields in 64-bit and
6e64c9
+	 *  maintain compatibility with old firmware.
6e64c9
+	 * This code assumes that <dummy header> and <padding2> are
6e64c9
+	 *  optional.
6e64c9
+	 */
6e64c9
+
6e64c9
+	if (skb->len < 4)
6e64c9
 		return 0;
6e64c9
-
6e64c9
 	skb_trim(skb, skb->len - 4);
6e64c9
 	rx_hdr = get_unaligned_le32(skb_tail_pointer(skb));
6e64c9
-
6e64c9
 	pkt_cnt = (u16)rx_hdr;
6e64c9
 	hdr_off = (u16)(rx_hdr >> 16);
6e64c9
+
6e64c9
+	if (pkt_cnt == 0)
6e64c9
+		return 0;
6e64c9
+
6e64c9
+	/* Make sure that the bounds of the metadata array are inside the SKB
6e64c9
+	 * (and in front of the counter at the end).
6e64c9
+	 */
6e64c9
+	if (pkt_cnt * 4 + hdr_off > skb->len)
6e64c9
+		return 0;
6e64c9
 	pkt_hdr = (u32 *)(skb->data + hdr_off);
6e64c9
 
6e64c9
-	while (pkt_cnt--) {
6e64c9
+	/* Packets must not overlap the metadata array */
6e64c9
+	skb_trim(skb, hdr_off);
6e64c9
+
6e64c9
+	for (; pkt_cnt > 0; pkt_cnt--, pkt_hdr++) {
6e64c9
+		u16 pkt_len_plus_padd;
6e64c9
 		u16 pkt_len;
6e64c9
 
6e64c9
 		le32_to_cpus(pkt_hdr);
6e64c9
 		pkt_len = (*pkt_hdr >> 16) & 0x1fff;
6e64c9
+		pkt_len_plus_padd = (pkt_len + 7) & 0xfff8;
6e64c9
+
6e64c9
+		/* Skip dummy header used for alignment
6e64c9
+		 */
6e64c9
+		if (pkt_len == 0)
6e64c9
+			continue;
6e64c9
+
6e64c9
+		if (pkt_len_plus_padd > skb->len)
6e64c9
+			return 0;
6e64c9
 
6e64c9
 		/* Check CRC or runt packet */
6e64c9
-		if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
6e64c9
-		    (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
6e64c9
-			skb_pull(skb, (pkt_len + 7) & 0xFFF8);
6e64c9
-			pkt_hdr++;
6e64c9
+		if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) ||
6e64c9
+		    pkt_len < 2 + ETH_HLEN) {
6e64c9
+			dev->net->stats.rx_errors++;
6e64c9
+			skb_pull(skb, pkt_len_plus_padd);
6e64c9
 			continue;
6e64c9
 		}
6e64c9
 
6e64c9
-		if (pkt_cnt == 0) {
6e64c9
-			skb->len = pkt_len;
6e64c9
+		/* last packet */
6e64c9
+		if (pkt_len_plus_padd == skb->len) {
6e64c9
+			skb_trim(skb, pkt_len);
6e64c9
+
6e64c9
 			/* Skip IP alignment pseudo header */
6e64c9
 			skb_pull(skb, 2);
6e64c9
-			skb_set_tail_pointer(skb, skb->len);
6e64c9
-			skb->truesize = pkt_len + sizeof(struct sk_buff);
6e64c9
+
6e64c9
+			skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd);
6e64c9
 			ax88179_rx_checksum(skb, pkt_hdr);
6e64c9
 			return 1;
6e64c9
 		}
6e64c9
 
6e64c9
 		ax_skb = skb_clone(skb, GFP_ATOMIC);
6e64c9
-		if (ax_skb) {
6e64c9
-			ax_skb->len = pkt_len;
6e64c9
-			/* Skip IP alignment pseudo header */
6e64c9
-			skb_pull(ax_skb, 2);
6e64c9
-			skb_set_tail_pointer(ax_skb, ax_skb->len);
6e64c9
-			ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
6e64c9
-			ax88179_rx_checksum(ax_skb, pkt_hdr);
6e64c9
-			usbnet_skb_return(dev, ax_skb);
6e64c9
-		} else {
6e64c9
+		if (!ax_skb)
6e64c9
 			return 0;
6e64c9
-		}
6e64c9
+		skb_trim(ax_skb, pkt_len);
6e64c9
+
6e64c9
+		/* Skip IP alignment pseudo header */
6e64c9
+		skb_pull(ax_skb, 2);
6e64c9
+
6e64c9
+		skb->truesize = pkt_len_plus_padd +
6e64c9
+				SKB_DATA_ALIGN(sizeof(struct sk_buff));
6e64c9
+		ax88179_rx_checksum(ax_skb, pkt_hdr);
6e64c9
+		usbnet_skb_return(dev, ax_skb);
6e64c9
 
6e64c9
-		skb_pull(skb, (pkt_len + 7) & 0xFFF8);
6e64c9
-		pkt_hdr++;
6e64c9
+		skb_pull(skb, pkt_len_plus_padd);
6e64c9
 	}
6e64c9
-	return 1;
6e64c9
+
6e64c9
+	return 0;
6e64c9
 }
6e64c9
 
6e64c9
 static struct sk_buff *
6e64c9
-- 
6e64c9
2.38.1
6e64c9
6e64c9