yellowfin: Fix buffer underrun after dev_alloc_skb() failure
Subsystems (2)
PATCH 1/1 yellowfin: Fix buffer underrun after dev_alloc_skb() failure
When dev_alloc_skb fails in the first iteration, a buffer underrun occurs.
---
Is this the best way to fix this? Untested, please review.
drivers/net/yellowfin.c +6 -1
@@ -728,7 +728,7 @@ static void yellowfin_tx_timeout(struct net_device *dev)static void yellowfin_init_ring (struct net_device *dev) {struct yellowfin_private *yp =netdev_priv (dev); -int i; +int i, j; yp->tx_full =0 ; yp->cur_rx = yp->cur_tx =0 ;
@@ -753,6 +753,11 @@ static void yellowfin_init_ring(struct net_device *dev) yp->rx_ring[i].addr =cpu_to_le32 (pci_map_single (yp->pci_dev, skb->data, yp->rx_buf_sz,PCI_DMA_FROMDEVICE )); } +if (i !=RX_RING_SIZE ) { +for (j =0 ; j < i; j++) +dev_kfree_skb (yp->rx_skbuff[j]); +return ; + } yp->rx_ring[i-1 ].dbdma_cmd =cpu_to_le32 (CMD_STOP ); yp->dirty_rx = (unsigned int )(i -RX_RING_SIZE );
David Miller
maintainerFrom: Roel Kluin <[email protected]>
Date: Fri, 07 Aug 2009 19:57:28 +0200
Quoted 5 lines
When
dev_alloc_skbfails in the first iteration, a buffer underrun occurs.Signed-off-by Roel Kluin <[email protected]>---
Is this the best way to fix this? Untested, please review.
I think this is a case where this code is going to need to be majorly reworked so that you can pass error status up to the caller when this allocation failure happens, and the caller can properly act upon it.
Just silently returning when no RX ring has been allocated, and the TX ring hasn't been setup at all, is going to be worse than the array overrun you're supposedly fixing.
When dev_alloc_skb fails in the first iteration, a buffer underrun occurs.
---
Quoted 8 lines
I think this is a case where this code is going to need to be majorly reworked so that you can pass error status up to the caller when this allocation failure happens, and the caller can properly act upon it.
Just silently returning when no RX ring has been allocated, and the TX ring hasn't been setup at all, is going to be worse than the array overrun you're supposedly fixing.
I think it should be something like this. Should yellowfin_open() do more than just passing the yellowfin_init_ring() error?
drivers/net/yellowfin.c +16 -10
@@ -346,7 +346,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int yellowfin_open (struct net_device *dev);static void yellowfin_timer (unsigned long data);static void yellowfin_tx_timeout (struct net_device *dev); -static void yellowfin_init_ring (struct net_device *dev); +static int yellowfin_init_ring (struct net_device *dev);static int yellowfin_start_xmit (struct sk_buff *skb,struct net_device *dev);static irqreturn_t yellowfin_interrupt (int irq,void *dev_instance);static int yellowfin_rx (struct net_device *dev);
@@ -573,19 +573,22 @@ static int yellowfin_open(struct net_device *dev) {struct yellowfin_private *yp =netdev_priv (dev);void __iomem *ioaddr = yp->base; -int i; +int i, ret;/* Reset the chip. */ iowrite32 (0x80000000 , ioaddr + DMACtrl); - i =request_irq (dev->irq, &yellowfin_interrupt,IRQF_SHARED , dev->name, dev); -if (i)return i; + ret =request_irq (dev->irq, &yellowfin_interrupt,IRQF_SHARED , dev->name, dev); +if (ret) +return ret;if (yellowfin_debug >1 )printk (KERN_DEBUG "%s: yellowfin_open() irq %d.\n" , dev->name, dev->irq); -yellowfin_init_ring (dev); + ret =yellowfin_init_ring (dev); +if (ret) +return ret;iowrite32 (yp->rx_ring_dma, ioaddr + RxPtr);iowrite32 (yp->tx_ring_dma, ioaddr + TxPtr);
@@ -725,10 +728,10 @@ static void yellowfin_tx_timeout(struct net_device *dev) }/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void yellowfin_init_ring (struct net_device *dev) +static int yellowfin_init_ring (struct net_device *dev) {struct yellowfin_private *yp =netdev_priv (dev); -int i; +int i, j; yp->tx_full =0 ; yp->cur_rx = yp->cur_tx =0 ;
@@ -753,6 +756,11 @@ static void yellowfin_init_ring(struct net_device *dev) yp->rx_ring[i].addr =cpu_to_le32 (pci_map_single (yp->pci_dev, skb->data, yp->rx_buf_sz,PCI_DMA_FROMDEVICE )); } +if (i !=RX_RING_SIZE ) { +for (j =0 ; j < i; j++) +dev_kfree_skb (yp->rx_skbuff[j]); +return -ENOMEM ; + } yp->rx_ring[i-1 ].dbdma_cmd =cpu_to_le32 (CMD_STOP ); yp->dirty_rx = (unsigned int )(i -RX_RING_SIZE );
@@ -769,8 +777,6 @@ static void yellowfin_init_ring(struct net_device *dev) yp->tx_ring[--i].dbdma_cmd =cpu_to_le32 (CMD_STOP |BRANCH_ALWAYS );#else { -int j; -/* Tx ring needs a pair of descriptors, the second for the status. */ for (i =0 ; i <TX_RING_SIZE ; i++) { j =2 *i;
@@ -805,7 +811,7 @@ static void yellowfin_init_ring(struct net_device *dev) }#endif yp->tx_tail_desc = &yp->tx_status[0 ]; -return ; +return 0 ; }static int yellowfin_start_xmit (struct sk_buff *skb,struct net_device *dev)
David Miller
maintainerFrom: Roel Kluin <[email protected]>
Date: Fri, 14 Aug 2009 11:59:14 +0200
Quoted 10 lines
drivers/net/yellowfin.c +3
-2/* Reset the chip. */ iowrite32 (0x80000000 , ioaddr + DMACtrl); - i =request_irq (dev->irq, &yellowfin_interrupt,IRQF_SHARED , dev->name, dev); -if (i)return i; + ret =request_irq (dev->irq, &yellowfin_interrupt,IRQF_SHARED , dev->name, dev); +if (ret) +return ret;if (yellowfin_debug >1 )
drivers/net/yellowfin.c static int yellowfin_open(struct net_device *dev) · line 594
Quoted 10 lines
drivers/net/yellowfin.c +3
-1printk (KERN_DEBUG "%s: yellowfin_open() irq %d.\n" , dev->name, dev->irq); -yellowfin_init_ring (dev); + ret =yellowfin_init_ring (dev); +if (ret) +return ret;iowrite32 (yp->rx_ring_dma, ioaddr + RxPtr);iowrite32 (yp->tx_ring_dma, ioaddr + TxPtr);
If yellowfin_init_ring() returns an error, you're leaking the IRQ allocated by request_irq().
yellowfin_init_ring() needs to clean up if dev_alloc_skb() fails and should pass an error status up to the caller. This also prevents an buffer underrun if failure occurred in the first iteration. yellowfin_open() which calls yellowfin_init_ring() should free its requested irq upon failure.
---
drivers/net/yellowfin.c +18 -10
@@ -346,7 +346,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int yellowfin_open (struct net_device *dev);static void yellowfin_timer (unsigned long data);static void yellowfin_tx_timeout (struct net_device *dev); -static void yellowfin_init_ring (struct net_device *dev); +static int yellowfin_init_ring (struct net_device *dev);static int yellowfin_start_xmit (struct sk_buff *skb,struct net_device *dev);static irqreturn_t yellowfin_interrupt (int irq,void *dev_instance);static int yellowfin_rx (struct net_device *dev);
@@ -573,19 +573,24 @@ static int yellowfin_open(struct net_device *dev) {struct yellowfin_private *yp =netdev_priv (dev);void __iomem *ioaddr = yp->base; -int i; +int i, ret;/* Reset the chip. */ iowrite32 (0x80000000 , ioaddr + DMACtrl); - i =request_irq (dev->irq, &yellowfin_interrupt,IRQF_SHARED , dev->name, dev); -if (i)return i; + ret =request_irq (dev->irq, &yellowfin_interrupt,IRQF_SHARED , dev->name, dev); +if (ret) +return ret;if (yellowfin_debug >1 )printk (KERN_DEBUG "%s: yellowfin_open() irq %d.\n" , dev->name, dev->irq); -yellowfin_init_ring (dev); + ret =yellowfin_init_ring (dev); +if (ret) { +free_irq (dev->irq, dev); +return ret; + }iowrite32 (yp->rx_ring_dma, ioaddr + RxPtr);iowrite32 (yp->tx_ring_dma, ioaddr + TxPtr);
@@ -725,10 +730,10 @@ static void yellowfin_tx_timeout(struct net_device *dev) }/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void yellowfin_init_ring (struct net_device *dev) +static int yellowfin_init_ring (struct net_device *dev) {struct yellowfin_private *yp =netdev_priv (dev); -int i; +int i, j; yp->tx_full =0 ; yp->cur_rx = yp->cur_tx =0 ;
@@ -753,6 +758,11 @@ static void yellowfin_init_ring(struct net_device *dev) yp->rx_ring[i].addr =cpu_to_le32 (pci_map_single (yp->pci_dev, skb->data, yp->rx_buf_sz,PCI_DMA_FROMDEVICE )); } +if (i !=RX_RING_SIZE ) { +for (j =0 ; j < i; j++) +dev_kfree_skb (yp->rx_skbuff[j]); +return -ENOMEM ; + } yp->rx_ring[i-1 ].dbdma_cmd =cpu_to_le32 (CMD_STOP ); yp->dirty_rx = (unsigned int )(i -RX_RING_SIZE );
@@ -769,8 +779,6 @@ static void yellowfin_init_ring(struct net_device *dev) yp->tx_ring[--i].dbdma_cmd =cpu_to_le32 (CMD_STOP |BRANCH_ALWAYS );#else { -int j; -/* Tx ring needs a pair of descriptors, the second for the status. */ for (i =0 ; i <TX_RING_SIZE ; i++) { j =2 *i;
@@ -805,7 +813,7 @@ static void yellowfin_init_ring(struct net_device *dev) }#endif yp->tx_tail_desc = &yp->tx_status[0 ]; -return ; +return 0 ; }static int yellowfin_start_xmit (struct sk_buff *skb,struct net_device *dev)
David Miller
maintainerFrom: Roel Kluin <[email protected]>
Date: Tue, 18 Aug 2009 10:50:34 +0200
Quoted 7 lines
yellowfin_init_ring()needs to clean up ifdev_alloc_skb()fails and should pass an error status up to the caller. This also prevents an buffer underrun if failure occurred in the first iteration.yellowfin_open()which callsyellowfin_init_ring()should free its requested irq upon failure.Signed-off-by Roel Kluin <[email protected]>
Looks good, applied, thanks.