Re: [PATCH 1/4] Ethernet drivers in 3.14-rc3 kernel: fix 3 buffer overflows triggered by hardware devices
From: Grant Grundler <hidden>
Date: 2014-02-22 03:12:08
On Fri, Feb 21, 2014 at 4:02 PM, Alon Nafta [off-list ref] wrote:
From: Alon Nafta <redacted> Linux Kernel contains multiple overflow conditions that are triggered as hardware-supplied inputs are not properly validated when parsing Ethernet packets. This may allow a local attacker to cause an overflow, resulting in a denial of service or potentially allowing the execution of arbitrary code. The programmatic error resides in the use of an integer type to describe packet length, without proper validation for negative values. In all three (3) bugs this patch fixes, a value of 0x30000 for the hardware signal, named status, will result in the value of 0xffffffff for pkt_len, and an allocation of a socket buffer with size of 0x1. This result in an overflow when data is copied into that buffer. Signed-off-by: Alon Nafta <redacted>
LGTM. Thanks! :) Reviewed-by: Grant Grundler <redacted>
quoted hunk
--- diff -uprN -X linux-3.14-rc3/Documentation/dontdiff linux-3.14-rc3-orig/drivers/net/ethernet/dec/tulip/de4x5.c linux-3.14-rc3/drivers/net/ethernet/dec/tulip/de4x5.c--- linux-3.14-rc3-orig/drivers/net/ethernet/dec/tulip/de4x5.c 2014-02-2017:59:14.704084300 -0800+++ linux-3.14-rc3/drivers/net/ethernet/dec/tulip/de4x5.c 2014-02-2018:23:08.987749400 -0800@@ -1635,8 +1635,8 @@ de4x5_rx(struct net_device *dev) if (status & RD_OF) lp->pktStats.rx_overflow++; } else { /* A valid frame received */ struct sk_buff *skb; - short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status) - >> 16) - 4; + short pkt_len = (short)((le32_to_cpu(lp->rx_ring[entry].status) + >> 16) - 4) & 0x7fff; if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { printk("%s: Insufficient memory; nuking packet.\n",diff -uprN -X linux-3.14-rc3/Documentation/dontdiff linux-3.14-rc3-orig/drivers/net/ethernet/dec/tulip/winbond-840.c linux-3.14-rc3/drivers/net/ethernet/dec/tulip/winbond-840.c--- linux-3.14-rc3-orig/drivers/net/ethernet/dec/tulip/winbond-840.c2014-02-20 17:59:14.757666100 -0800+++ linux-3.14-rc3/drivers/net/ethernet/dec/tulip/winbond-840.c 2014-02-2018:22:19.419612200 -0800@@ -1218,7 +1218,7 @@ static int netdev_rx(struct net_device * } else { struct sk_buff *skb; /* Omit the four octet CRC from the length. */ - int pkt_len = ((status >> 16) & 0x7ff) - 4; + int pkt_len = ((status >> 16) - 4) & 0x7ff; #ifndef final_version if (debug > 4)diff -uprN -X linux-3.14-rc3/Documentation/dontdiff linux-3.14-rc3-orig/drivers/net/ethernet/smsc/epic100.c linux-3.14-rc3/drivers/net/ethernet/smsc/epic100.c--- linux-3.14-rc3-orig/drivers/net/ethernet/smsc/epic100.c 2014-02-2017:59:17.844045500 -0800+++ linux-3.14-rc3/drivers/net/ethernet/smsc/epic100.c 2014-02-2018:21:13.196237400 -0800@@ -1172,7 +1172,7 @@ static int epic_rx(struct net_device *de } else { /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ - short pkt_len = (status >> 16) - 4; + short pkt_len = ((status >> 16) - 4) & 0x7fff; struct sk_buff *skb; if (pkt_len > PKT_BUF_SZ - 4) {