Commit 411aa79d authored by Yusuf Wilajati Purna's avatar Yusuf Wilajati Purna Committed by Jeff Garzik

[netdrvr] fix skb_padto bugs introduced when skb_padto was introduced

It seems that skb_padto security fixes in 2.4 and 2.5 trying
to fix "CAN-2003-0001:Multiple ethernet NID device drivers
do not pad frames with null bytes", do not put the skb_padto
blocks in proper places in the  3c527, eth16i, fmv18x, seeq8005,
yellowfin device drivers.   

In case a driver calls skb_padto(), it is possible
that the space available in the original skb buffer tailroom is less
than the space to pad. In this case, in short, the skb_padto()
will create a new skb buffer, copy data from the original
skb buffer to a new skb buffer, free the original buffer,
and finally return the new buffer.

If this happens to the aforementioned device drivers, they come to
point to wrong data. And, for 3c527 and yellowfin, the drivers can
unexpectedly double free the original skb buffers since they still
point to the original skb buffers. The attached patch against
2.4.23pre1 fixes these issues.
parent 8bf3a2c6
...@@ -1081,14 +1081,15 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -1081,14 +1081,15 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
/* NP is the buffer we will be loading */ /* NP is the buffer we will be loading */
np=lp->tx_ring[lp->tx_ring_head].p; np=lp->tx_ring[lp->tx_ring_head].p;
/* We will need this to flush the buffer out */
lp->tx_ring[lp->tx_ring_head].skb=skb;
if (skb->len < ETH_ZLEN) { if (skb->len < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN); skb = skb_padto(skb, ETH_ZLEN);
if (skb == NULL) if (skb == NULL)
goto out; goto out;
} }
/* We will need this to flush the buffer out */
lp->tx_ring[lp->tx_ring_head].skb = skb;
np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
np->data = isa_virt_to_bus(skb->data); np->data = isa_virt_to_bus(skb->data);
......
...@@ -1053,7 +1053,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -1053,7 +1053,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
int status = 0; int status = 0;
ushort length = skb->len; ushort length = skb->len;
unsigned char *buf = skb->data; unsigned char *buf;
unsigned long flags; unsigned long flags;
if (length < ETH_ZLEN) { if (length < ETH_ZLEN) {
...@@ -1062,6 +1062,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -1062,6 +1062,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
length = ETH_ZLEN; length = ETH_ZLEN;
} }
buf = skb->data;
netif_stop_queue(dev); netif_stop_queue(dev);
......
...@@ -367,7 +367,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -367,7 +367,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
struct net_local *lp = dev->priv; struct net_local *lp = dev->priv;
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
short length = skb->len; short length = skb->len;
unsigned char *buf = skb->data; unsigned char *buf;
unsigned long flags; unsigned long flags;
/* Block a transmit from overlapping. */ /* Block a transmit from overlapping. */
...@@ -385,6 +385,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -385,6 +385,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
length = ETH_ZLEN; length = ETH_ZLEN;
} }
buf = skb->data;
if (net_debug > 4) if (net_debug > 4)
printk("%s: Transmitting a packet of length %lu.\n", dev->name, printk("%s: Transmitting a packet of length %lu.\n", dev->name,
......
...@@ -378,7 +378,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -378,7 +378,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
{ {
struct net_local *lp = (struct net_local *)dev->priv; struct net_local *lp = (struct net_local *)dev->priv;
short length = skb->len; short length = skb->len;
unsigned char *buf = skb->data; unsigned char *buf;
if (length < ETH_ZLEN) { if (length < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN); skb = skb_padto(skb, ETH_ZLEN);
...@@ -386,6 +386,8 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -386,6 +386,8 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
length = ETH_ZLEN; length = ETH_ZLEN;
} }
buf = skb->data;
/* Block a timer-based transmit from overlapping */ /* Block a timer-based transmit from overlapping */
netif_stop_queue(dev); netif_stop_queue(dev);
......
...@@ -873,8 +873,6 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -873,8 +873,6 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Calculate the next Tx descriptor entry. */ /* Calculate the next Tx descriptor entry. */
entry = yp->cur_tx % TX_RING_SIZE; entry = yp->cur_tx % TX_RING_SIZE;
yp->tx_skbuff[entry] = skb;
if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */ if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */
int cacheline_end = ((unsigned long)skb->data + skb->len) % 32; int cacheline_end = ((unsigned long)skb->data + skb->len) % 32;
/* Fix GX chipset errata. */ /* Fix GX chipset errata. */
...@@ -889,6 +887,8 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -889,6 +887,8 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
} }
yp->tx_skbuff[entry] = skb;
#ifdef NO_TXSTATS #ifdef NO_TXSTATS
yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
skb->data, len, PCI_DMA_TODEVICE)); skb->data, len, PCI_DMA_TODEVICE));
......
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