Blame SOURCES/CVE-2022-2964.patch

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