From: Ana Bobillo <[email protected]>
r8152_eth_recv() reads the rx descriptor at the start of what is left of
the transfer without checking that a whole descriptor is there, and then
bounds the packet length with
if (packet_len > len - (sizeof(struct rx_desc) + CRC_SIZE))
which is evaluated in size_t: when fewer than 28 bytes are left it wraps
and lets any packet length through, including one that wrapped in its
u16 because the descriptor gave a length below CRC_SIZE. A short
transfer from the adapter then hands the network stack a packet whose
start and length run past the received data, and past the end of the
2 KiB receive buffer.
Require a whole descriptor and CRC before reading the descriptor, and
work in int so that neither length can wrap.
Signed-off-by: Ana Bobillo <[email protected]>
---
drivers/usb/eth/r8152.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c
index e3f20e08c33..19b3f0bc22a 100644
--- a/drivers/usb/eth/r8152.c
+++ b/drivers/usb/eth/r8152.c
@@ -1471,9 +1471,8 @@ int r8152_eth_recv(struct udevice *dev, int flags, uchar
**packetp)
struct r8152 *tp = dev_get_priv(dev);
struct ueth_data *ueth = &tp->ueth;
uint8_t *ptr;
- int ret, len;
+ int ret, len, packet_len;
struct rx_desc *rx_desc;
- u16 packet_len;
len = usb_ether_get_rx_bytes(ueth, &ptr);
debug("%s: first try, len=%d\n", __func__, len);
@@ -1488,12 +1487,18 @@ int r8152_eth_recv(struct udevice *dev, int flags,
uchar **packetp)
debug("%s: second try, len=%d\n", __func__, len);
}
+ if (len < (int)(sizeof(struct rx_desc) + CRC_SIZE)) {
+ debug("Rx: incomplete packet: %d\n", len);
+ goto err;
+ }
+
rx_desc = (struct rx_desc *)ptr;
packet_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
packet_len -= CRC_SIZE;
- if (packet_len > len - (sizeof(struct rx_desc) + CRC_SIZE)) {
- debug("Rx: too large packet: %d\n", packet_len);
+ if (packet_len < 0 ||
+ packet_len > len - (int)(sizeof(struct rx_desc) + CRC_SIZE)) {
+ debug("Rx: bad packet length: %d\n", packet_len);
goto err;
}