Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd224553 authored by Anssi Hannula's avatar Anssi Hannula Committed by David S. Miller
Browse files

net: xilinx_emaclite: fix receive buffer overflow



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>
parent 5463b3d0
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -369,7 +369,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;
@@ -409,7 +409,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(__raw_readl(addr +
@@ -417,6 +417,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)
@@ -429,6 +430,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);
@@ -603,7 +607,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++;