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

Reply via email to