From: Ana Bobillo <[email protected]>
ax88179_eth_recv() takes the packet count and the offset of the packet
headers from the rx header at the end of the transfer, and checks only
that the offset lies inside the transfer. The count is not bounded, so
the driver walks packet headers past the rx header and the received
data, and no packet length is bounded either, so a packet, and the
start of the next one, can run past the received data.
Check what Linux ax88179_rx_fixup() checks since commit 57bc3d3ae8c1
("net: usb: ax88179_178a: Fix out-of-bounds accesses in RX fixup"): the
packet headers must fit between their offset and the rx header, and each
packet with its padding in front of the packet headers. Keep the end of
the packet data in asix_private for that, and drop the rest of the
transfer when a packet does not fit.
Signed-off-by: Ana Bobillo <[email protected]>
---
drivers/usb/eth/asix88179.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c
index 69d3073b669..4c6c9b2796e 100644
--- a/drivers/usb/eth/asix88179.c
+++ b/drivers/usb/eth/asix88179.c
@@ -204,6 +204,7 @@ struct asix_private {
struct ueth_data ueth;
unsigned pkt_cnt;
uint8_t *pkt_data;
+ uint8_t *pkt_end;
uint32_t *pkt_hdr;
int flags;
int rx_urb_size;
@@ -543,6 +544,7 @@ void ax88179_eth_stop(struct udevice *dev)
usb_ether_advance_rxbuf(ueth, -1);
priv->pkt_cnt = 0;
priv->pkt_data = NULL;
+ priv->pkt_end = NULL;
priv->pkt_hdr = NULL;
}
@@ -595,14 +597,16 @@ int ax88179_eth_recv(struct udevice *dev, int flags,
uchar **packetp)
return 0;
}
+ /* The packet headers must lie in front of rx_hdr */
hdr_off = (u16)(rx_hdr >> 16);
- if (hdr_off > len - 4) {
+ if (hdr_off + 4 * pkt_cnt > len - 4) {
usb_ether_advance_rxbuf(ueth, -1);
return -EIO;
}
priv->pkt_cnt = pkt_cnt;
priv->pkt_data = ptr;
+ priv->pkt_end = ptr + hdr_off;
priv->pkt_hdr = (u32 *)(ptr + hdr_off);
debug("%s: %d packets received, pkt header at %d\n",
__func__, (int)priv->pkt_cnt, (int)hdr_off);
@@ -611,6 +615,13 @@ int ax88179_eth_recv(struct udevice *dev, int flags, uchar
**packetp)
le32_to_cpus(priv->pkt_hdr);
pkt_len = (*priv->pkt_hdr >> 16) & 0x1fff;
+ /* The packet and its padding must lie in front of the packet headers */
+ if (((pkt_len + 7) & 0xFFF8) > priv->pkt_end - priv->pkt_data) {
+ priv->pkt_cnt = 0;
+ usb_ether_advance_rxbuf(ueth, -1);
+ return -EIO;
+ }
+
*packetp = priv->pkt_data + 2;
priv->pkt_data += (pkt_len + 7) & 0xFFF8;