143 lines
2.9 KiB
Diff
143 lines
2.9 KiB
Diff
|
From: Neil Horman <nhorman@tuxdriver.com>
|
||
|
Subject: [PATCH] e1000e: enhance frame fragment detection
|
||
|
References: bnc#567376, CVE-2009-4538
|
||
|
|
||
|
A security discussion was recently given:
|
||
|
http://events.ccc.de/congress/2009/Fahrplan//events/3596.en.html And a patch
|
||
|
that I submitted awhile back was brought up. Apparently some of their testing
|
||
|
revealed that they were able to force a buffer fragment in e1000e in which the
|
||
|
trailing fragment was greater than 4 bytes. As a result the fragment check I
|
||
|
introduced failed to detect the fragement and a partial invalid frame was
|
||
|
passed up into the network stack. I've written this patch to correct it. I'm
|
||
|
in the process of testing it now, but it makes good logical sense to me.
|
||
|
Effectively it maintains a per-adapter state variable which detects a non-EOP
|
||
|
frame, and discards it and subsequent non-EOP frames leading up to _and_
|
||
|
_including_ the next positive-EOP frame (as it is by definition the last
|
||
|
fragment). This should prevent any and all partial frames from entering the
|
||
|
network stack from e1000e
|
||
|
|
||
|
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
|
||
|
Signed-off-by: Brandon Philips <bphilips@suse.de>
|
||
|
---
|
||
|
drivers/net/e1000e/e1000.h | 3 ++-
|
||
|
drivers/net/e1000e/netdev.c | 13 +++++++++++--
|
||
|
2 files changed, 13 insertions(+), 3 deletions(-)
|
||
|
|
||
|
Index: linux-2.6.31-openSUSE-11.2/drivers/net/e1000e/e1000.h
|
||
|
===================================================================
|
||
|
--- linux-2.6.31-openSUSE-11.2.orig/drivers/net/e1000e/e1000.h
|
||
|
+++ linux-2.6.31-openSUSE-11.2/drivers/net/e1000e/e1000.h
|
||
|
@@ -412,7 +412,8 @@ struct e1000_info {
|
||
|
enum e1000_state_t {
|
||
|
__E1000_TESTING,
|
||
|
__E1000_RESETTING,
|
||
|
- __E1000_DOWN
|
||
|
+ __E1000_DOWN,
|
||
|
+ __E1000_DISCARDING
|
||
|
};
|
||
|
|
||
|
enum latency_range {
|
||
|
Index: linux-2.6.31-openSUSE-11.2/drivers/net/e1000e/netdev.c
|
||
|
===================================================================
|
||
|
--- linux-2.6.31-openSUSE-11.2.orig/drivers/net/e1000e/netdev.c
|
||
|
+++ linux-2.6.31-openSUSE-11.2/drivers/net/e1000e/netdev.c
|
||
|
@@ -483,12 +483,21 @@ static bool e1000_clean_rx_irq(struct e1
|
||
|
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->state);
|
||
|
+
|
||
|
+ if (test_bit(__E1000_DISCARDING, &adapter->state)) {
|
||
|
/* All receives must fit into a single buffer */
|
||
|
e_dbg("Receive packet consumed multiple buffers\n");
|
||
|
/* recycle */
|
||
|
buffer_info->skb = skb;
|
||
|
+ if (status & E1000_RXD_STAT_EOP)
|
||
|
+ clear_bit(__E1000_DISCARDING, &adapter->state);
|
||
|
goto next_desc;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|