Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2590

kernel-2.6.18-238.el5.src.rpm

From: Amerigo Wang <amwang@redhat.com>
Date: Thu, 14 Jan 2010 15:36:38 -0500
Subject: [net] e1000e: fix rx length check errors
Bugzilla: 551223
CVE: CVE-2009-4538

BZ:
https://bugzilla.redhat.com/show_bug.cgi?id=551223

Description:
Quote the original description of Neil for the problem:

Apparently a security conf was held a few days ago:
http://events.ccc.de/congress/2009/Fahrplan//events/3596.en.html

In which some length check exploits were listed for e1000 and r8169.  I've
written the following patches, and am in the process of testing them.

Upstream discussions can be followed here:
http://marc.info/?l=linux-netdev&m=126203101730472&w=2
http://marc.info/?l=linux-netdev&m=126202972828626&w=2

This patch is just for the e1000e part, very similar to e1000 part.

Brew:
(this one together with the one from Neil, with a compile error fixed)
https://brewweb.devel.redhat.com/taskinfo?taskID=2169141

Signed-off-by: WANG Cong <amwang@redhat.com>

diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 944af96..1f753c7 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -427,7 +427,8 @@ struct e1000_info {
 enum e1000_state_t {
 	__E1000_TESTING,
 	__E1000_RESETTING,
-	__E1000_DOWN
+	__E1000_DOWN,
+	__E1000_DISCARDING
 };
 
 enum latency_range {
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index cc29cea..239ace8 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -485,13 +485,22 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 		length = le16_to_cpu(rx_desc->length);
 
 		/* !EOP means multiple descriptors were used to store a single
-		 * packet, also make sure the frame isn't just CRC only */
-		if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) {
+		 * packet, if thats the case we need to toss it.  In fact, we
+		 * to toss every packet with the EOP bit clear and the next
+		 * frame that _does_ have the EOP bit set, as it is by
+		 * definition only a frame fragment
+		 */
+		if (unlikely(!(status & E1000_RXD_STAT_EOP)))
+			set_bit(__E1000_DISCARDING, &adapter->flags);
+
+		if (test_bit(__E1000_DISCARDING, &adapter->flags)) {
 			/* All receives must fit into a single buffer */
 			e_dbg("%s: Receive packet consumed multiple buffers\n",
 			      netdev->name);
 			/* recycle */
 			buffer_info->skb = skb;
+			if (status & E1000_RXD_STAT_EOP)
+				clear_bit(__E1000_DISCARDING, &adapter->flags);
 			goto next_desc;
 		}