Commit b9ad9bb6 authored by Jesse Brandeburg's avatar Jesse Brandeburg Committed by Greg Kroah-Hartman

e1000e: enhance frame fragment detection

commit b94b5028 upstream.

Originally patched by Neil Horman <nhorman@tuxdriver.com>

e1000e could with a jumbo frame enabled interface, and packet split disabled,
receive a packet that would overflow a single rx buffer.  While in practice
very hard to craft a packet that could abuse this, it is possible.

this is related to CVE-2009-4538
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
CC: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dff2267e
...@@ -417,6 +417,7 @@ struct e1000_info { ...@@ -417,6 +417,7 @@ struct e1000_info {
/* CRC Stripping defines */ /* CRC Stripping defines */
#define FLAG2_CRC_STRIPPING (1 << 0) #define FLAG2_CRC_STRIPPING (1 << 0)
#define FLAG2_HAS_PHY_WAKEUP (1 << 1) #define FLAG2_HAS_PHY_WAKEUP (1 << 1)
#define FLAG2_IS_DISCARDING (1 << 2)
#define E1000_RX_DESC_PS(R, i) \ #define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
......
...@@ -482,14 +482,24 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, ...@@ -482,14 +482,24 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
length = le16_to_cpu(rx_desc->length); 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 */ * !EOP means multiple descriptors were used to store a single
if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { * packet, if that's the case we need to toss it. In fact, we
* need 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)))
adapter->flags2 |= FLAG2_IS_DISCARDING;
if (adapter->flags2 & FLAG2_IS_DISCARDING) {
/* All receives must fit into a single buffer */ /* All receives must fit into a single buffer */
e_dbg("%s: Receive packet consumed multiple buffers\n", e_dbg("%s: Receive packet consumed multiple buffers\n",
netdev->name); netdev->name);
/* recycle */ /* recycle */
buffer_info->skb = skb; buffer_info->skb = skb;
if (status & E1000_RXD_STAT_EOP)
adapter->flags2 &= ~FLAG2_IS_DISCARDING;
goto next_desc; goto next_desc;
} }
...@@ -747,10 +757,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, ...@@ -747,10 +757,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);
buffer_info->dma = 0; buffer_info->dma = 0;
if (!(staterr & E1000_RXD_STAT_EOP)) { /* see !EOP comment in other rx routine */
if (!(staterr & E1000_RXD_STAT_EOP))
adapter->flags2 |= FLAG2_IS_DISCARDING;
if (adapter->flags2 & FLAG2_IS_DISCARDING) {
e_dbg("%s: Packet Split buffers didn't pick up the " e_dbg("%s: Packet Split buffers didn't pick up the "
"full packet\n", netdev->name); "full packet\n", netdev->name);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
if (staterr & E1000_RXD_STAT_EOP)
adapter->flags2 &= ~FLAG2_IS_DISCARDING;
goto next_desc; goto next_desc;
} }
...@@ -1120,6 +1136,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter) ...@@ -1120,6 +1136,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
rx_ring->next_to_clean = 0; rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0; rx_ring->next_to_use = 0;
adapter->flags2 &= ~FLAG2_IS_DISCARDING;
writel(0, adapter->hw.hw_addr + rx_ring->head); writel(0, adapter->hw.hw_addr + rx_ring->head);
writel(0, adapter->hw.hw_addr + rx_ring->tail); writel(0, adapter->hw.hw_addr + rx_ring->tail);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment