|
|
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 |
|