[PATCH 3.10 094/139] net: xilinx_emaclite: fix receive buffer overflow

From: Willy Tarreau
Date: Wed Nov 01 2017 - 17:27:49 EST


From: Anssi Hannula <anssi.hannula@xxxxxxxxxx>

commit cd224553641848dd17800fe559e4ff5d208553e8 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: Anssi Hannula <anssi.hannula@xxxxxxxxxx>
Fixes: bb81b2ddfa19 ("net: add Xilinx emac lite device driver")
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
Signed-off-by: Willy Tarreau <w@xxxxxx>
---
drivers/net/ethernet/xilinx/xilinx_emaclite.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index b7268b3..5f5f84a 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -398,7 +398,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data,
*
* 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;
u16 length, proto_type;
@@ -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
* 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) {
length = ((ntohl(in_be32(addr +
@@ -446,6 +446,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
XEL_RXBUFF_OFFSET)) >>
XEL_HEADER_SHIFT) &
XEL_RPLR_LENGTH_MASK);
+ length = min_t(u16, length, ETH_DATA_LEN);
length += ETH_HLEN + ETH_FCS_LEN;

} else if (proto_type == ETH_P_ARP)
@@ -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 */
length = proto_type + ETH_HLEN + ETH_FCS_LEN;

+ if (WARN_ON(length > maxlen))
+ length = maxlen;
+
/* Read from the EmacLite device */
xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET),
data, length);
@@ -632,7 +636,7 @@ static void xemaclite_rx_handler(struct net_device *dev)

skb_reserve(skb, 2);

- len = xemaclite_recv_data(lp, (u8 *) skb->data);
+ len = xemaclite_recv_data(lp, (u8 *) skb->data, len);

if (!len) {
dev->stats.rx_errors++;
--
2.8.0.rc2.1.gbe9624a