From: Neil Horman <nhorman@redhat.com> Date: Tue, 2 Jun 2009 07:10:01 -0400 Subject: [net] e1000: fix skb_over_panic Message-id: 20090602111001.GD17744@hmsreliant.think-freely.org O-Subject: [kernel team] [RHEL 5.4][EMBARGOED] e1000: fix skb_over_panic (bz 503441) Bugzilla: 503441 RH-Acked-by: Jiri Pirko <jpirko@redhat.com> RH-Acked-by: John W. Linville <linville@redhat.com> RH-Acked-by: Andy Gospodarek <gospo@redhat.com> RH-Acked-by: Eugene Teo <eugene@redhat.com> CVE: CVE-2009-1385 Hey all- This bug came in yesterday, apparently a customer reported that setting the mtu on an interface very low and sending in a very large icmp echo request results in an skb_over_panic on e1000 cards, which has been considered a denial of service attack on RHEL4. Gospo and I did some research, and he found that (quite unexpectedly), we're getting this panic because we try to do an skb_put on a buffer, passing in a length value that underflowed, resulting in a huge positive value. Doing some reading, it appears that e1000 (and all its brethren hardware), appear to consistently allow packets to span multiple rx descriptors, occasionally leading to a frame who's crc checksum is partially contained in a separate descriptor. None of the intel drivers are written to handle this packet span condition, and so they simply discard the frame by checking the EOP bit in the rx status word for the frame. That handles the first part of the packet, but the second part, which is usually very small has the EOP bit set and so passes through. Since the driver trucates the packet by 4 bytes to remove the crc, if only part of the crc is available in the second packet, the length value underflows and we panic. Intels other drivers (e1000e, and I think ixgb) handle this by also discarding any packets less than 4 bytes, but they never bothered to port that fix over to e1000 in the upstream tree. This patch corrects that. Tested by Gospo and myself. Neil diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 96baf8d..cb5b9bd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4233,7 +4233,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, length = le16_to_cpu(rx_desc->length); - if (unlikely(!(status & E1000_RXD_STAT_EOP))) { + if (unlikely(!(status & E1000_RXD_STAT_EOP) || (length <= 4))) { /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" " buffers\n", netdev->name);