| From: Anssi Hannula <anssi.hannula@bitwise.fi> |
| Date: Tue, 14 Feb 2017 19:11:44 +0200 |
| Subject: 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: bb81b2ddfa19 ("net: add Xilinx emac lite device driver") |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/net/ethernet/xilinx/xilinx_emaclite.c | 10 +++++++--- |
| 1 file changed, 7 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c |
| +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c |
| @@ -371,7 +371,7 @@ static int xemaclite_send_data(struct ne |
| * |
| * 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; |
| @@ -411,7 +411,7 @@ static u16 xemaclite_recv_data(struct ne |
| |
| /* 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 + |
| @@ -419,6 +419,7 @@ static u16 xemaclite_recv_data(struct ne |
| 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) |
| @@ -431,6 +432,9 @@ static u16 xemaclite_recv_data(struct ne |
| /* 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); |
| @@ -605,7 +609,7 @@ static void xemaclite_rx_handler(struct |
| |
| 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++; |