Commit 4091620d authored by Anssi Hannula's avatar Anssi Hannula Committed by Ben Hutchings

net: xilinx_emaclite: fix receive buffer overflow

commit cd224553 upstream.

xilinx_emaclite looks at the received data to try to determine the
Ethernet packet length but does not properly clamp it if
proto_type == ETH_P_IP or 1500 < proto_type <= 1518, causing a buffer
overflow and a panic via skb_panic() as the length exceeds the allocated
skb size.

Fix those cases.

Also add an additional unconditional check with WARN_ON() at the end.
Signed-off-by: default avatarAnssi Hannula <anssi.hannula@bitwise.fi>
Fixes: bb81b2dd ("net: add Xilinx emac lite device driver")
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent f606625d
...@@ -398,7 +398,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, ...@@ -398,7 +398,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data,
* *
* Return: Total number of bytes received * Return: Total number of bytes received
*/ */
static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen)
{ {
void __iomem *addr; void __iomem *addr;
u16 length, proto_type; u16 length, proto_type;
...@@ -438,7 +438,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) ...@@ -438,7 +438,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
/* Check if received ethernet frame is a raw ethernet frame /* Check if received ethernet frame is a raw ethernet frame
* or an IP packet or an ARP packet */ * or an IP packet or an ARP packet */
if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) { if (proto_type > ETH_DATA_LEN) {
if (proto_type == ETH_P_IP) { if (proto_type == ETH_P_IP) {
length = ((ntohl(in_be32(addr + length = ((ntohl(in_be32(addr +
...@@ -446,6 +446,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) ...@@ -446,6 +446,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
XEL_RXBUFF_OFFSET)) >> XEL_RXBUFF_OFFSET)) >>
XEL_HEADER_SHIFT) & XEL_HEADER_SHIFT) &
XEL_RPLR_LENGTH_MASK); XEL_RPLR_LENGTH_MASK);
length = min_t(u16, length, ETH_DATA_LEN);
length += ETH_HLEN + ETH_FCS_LEN; length += ETH_HLEN + ETH_FCS_LEN;
} else if (proto_type == ETH_P_ARP) } else if (proto_type == ETH_P_ARP)
...@@ -458,6 +459,9 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) ...@@ -458,6 +459,9 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
/* Use the length in the frame, plus the header and trailer */ /* Use the length in the frame, plus the header and trailer */
length = proto_type + ETH_HLEN + ETH_FCS_LEN; length = proto_type + ETH_HLEN + ETH_FCS_LEN;
if (WARN_ON(length > maxlen))
length = maxlen;
/* Read from the EmacLite device */ /* Read from the EmacLite device */
xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET), xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET),
data, length); data, length);
...@@ -632,7 +636,7 @@ static void xemaclite_rx_handler(struct net_device *dev) ...@@ -632,7 +636,7 @@ static void xemaclite_rx_handler(struct net_device *dev)
skb_reserve(skb, 2); skb_reserve(skb, 2);
len = xemaclite_recv_data(lp, (u8 *) skb->data); len = xemaclite_recv_data(lp, (u8 *) skb->data, len);
if (!len) { if (!len) {
dev->stats.rx_errors++; dev->stats.rx_errors++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment