net: xilinx_emaclite: fix receive buffer overflow
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@bitwise.fi>
Fixes: bb81b2ddfa ("net: add Xilinx emac lite device driver")
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Willy Tarreau <w@1wt.eu>
This commit is contained in:
committed by
Willy Tarreau
parent
7e25c935ec
commit
f6b525b94b
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user