net: sxgbe: Fix waring for double kfree()
Subsystems (4)
PATCH 1/1 net: sxgbe: Fix waring for double kfree()
From: Byungho An <[email protected]>
This patch fixes double kfree() calls at init_rx_ring() because it causes static checker warning.
--- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +10 -11
@@ -474,13 +474,19 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,/* allocate memory for RX skbuff array */ rx_ring->rx_skbuff_dma =kmalloc_array (rx_rsize,sizeof (dma_addr_t),GFP_KERNEL ); -if (rx_ring->rx_skbuff_dma ==NULL ) - goto dmamem_err; +if (!rx_ring->rx_skbuff_dma) { +dma_free_coherent (priv->device, + rx_rsize *sizeof (struct sxgbe_rx_norm_desc ), + rx_ring->dma_rx, rx_ring->dma_rx_phy); + goto error; + } rx_ring->rx_skbuff =kmalloc_array (rx_rsize,sizeof (struct sk_buff *),GFP_KERNEL ); -if (rx_ring->rx_skbuff ==NULL ) - goto rxbuff_err; +if (!rx_ring->rx_skbuff) { +kfree (rx_ring->rx_skbuff_dma); + goto error; + }/* initialise the buffers */ for (desc_index =0 ; desc_index < rx_rsize; desc_index++) {
@@ -502,13 +508,6 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, err_init_rx_buffers:while (--desc_index >=0 )free_rx_ring (priv->device, rx_ring, desc_index); -kfree (rx_ring->rx_skbuff); -rxbuff_err: -kfree (rx_ring->rx_skbuff_dma); -dmamem_err: -dma_free_coherent (priv->device, - rx_rsize *sizeof (struct sxgbe_rx_norm_desc ), - rx_ring->dma_rx, rx_ring->dma_rx_phy); error:return -ENOMEM ; }
Signature · 1 line
2.0.0
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c static int init_rx_ring(struct net_device *dev, u8 queue_no, · line 486
Quoted 5 lines · Kukjin Kim
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +1
-2rx_ring->rx_skbuff =kmalloc_array (rx_rsize,sizeof (struct sk_buff *),GFP_KERNEL ); -if (rx_ring->rx_skbuff ==NULL ) - goto rxbuff_err; +if (!rx_ring->rx_skbuff) {
This is missing a dma_free_coherent() here.
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c static int init_rx_ring(struct net_device *dev, u8 queue_no, · line 505
Quoted 11 lines
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +3
-1+kfree (rx_ring->rx_skbuff_dma); + goto error; + }/* initialise the buffers */ for (desc_index =0 ; desc_index < rx_rsize; desc_index++) {@@ -502,13 +508,6 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, err_init_rx_buffers:while (--desc_index >=0 )free_rx_ring (priv->device, rx_ring, desc_index); -kfree (rx_ring->rx_skbuff);
The double free bug is that free_rx_ring() frees kfree(rx_ring->rx_skbuff_dma); and kfree(rx_ring->rx_skbuff); so just calling it in a loop here will cause a double free.
Also free_rx_ring() doesn't take an index parameter, it takes a size parameter.
The right way to fix this is to create a release function that mirrors sxgbe_init_rx_buffers().
static void sxgbe_free_rx_buffers(struct net_device *dev,
struct sxgbe_rx_norm_desc *p, int i, unsigned int dma_buf_sz, struct sxgbe_rx_queue *rx_ring)
{
struct sxgbe_priv_data *priv = netdev_priv(dev);
kfree_skb(rx_ring->rx_skbuff[i]);
dma_unmap_single(priv->device, rx_ring->rx_skbuff_dma[i],
dma_buf_sz, DMA_FROM_DEVICE);
}Then just swap that into the free loop instead of the free_rx_ring().
err_init_rx_buffers:
while (--desc_index >= 0) {
struct sxgbe_rx_norm_desc *p;
p = rx_ring->dma_rx + desc_index;
sxgbe_init_rx_buffers(dev, p, desc_index, bfsize, rx_ring);
}
kfree(rx_ring->rx_skbuff);Something like that.
regards,
dan carpenter
From: Kukjin Kim <[email protected]>
Date: Thu, 15 Jan 2015 10:43:11 +0900
Quoted 8 lines
From: Byungho An <[email protected]>
This patch fixes double
kfree()calls atinit_rx_ring()because it causes static checker warning.Reported-by Dan Carpenter <[email protected]>Signed-off-by Byungho An <[email protected]>Signed-off-by Kukjin Kim <[email protected]>
Applied.
Quoted 5 lines · David Miller
From: Kukjin Kim <[email protected]>
Date: Thu, 15 Jan 2015 10:43:11 +0900Quoted 2 lines
From: Byungho An <[email protected]>
Quoted 8 lines
Quoted 6 lines
This patch fixes double
kfree()calls atinit_rx_ring()because it causes static checker warning.Reported-by Dan Carpenter <[email protected]>Signed-off-by Byungho An <[email protected]>Signed-off-by Kukjin Kim <[email protected]>Applied.
It does silence the warning but it doesn't fix the bug.
Kukjin, let me know if you have any questions. I can write the fix if you need me to.
regards,
dan carpenter
PATCH 1/1 net: sxgbe: fix error handling in init_rx_ring()
There are a couple bugs with the error handling in this function.
1) If we can't allocate "rx_ring->rx_skbuff" then we should call dma_free_coherent() but we don't.
2) free_rx_ring() frees "rx_ring->rx_skbuff_dma" and "rx_ring->rx_skbuff" so calling it in a loop causes a double free.
Also it was a bit confusing how we sometimes freed things before doing the goto. I've cleaned it up so it does error handling in normal kernel style.
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +43 -14
@@ -364,6 +364,26 @@ static int sxgbe_init_rx_buffers(struct net_device *dev,return 0 ; } + +/** +* sxgbe_free_rx_buffers - free what sxgbe_init_rx_buffers() allocated +* @dev: net device structure +* @rx_ring: ring to be freed +* @rx_rsize: ring size +* Description: this function initializes the DMA RX descriptor +*/ +static void sxgbe_free_rx_buffers (struct net_device *dev, +struct sxgbe_rx_norm_desc *p,int i, +unsigned int dma_buf_sz, +struct sxgbe_rx_queue *rx_ring) +{ +struct sxgbe_priv_data *priv =netdev_priv (dev); + +kfree_skb (rx_ring->rx_skbuff[i]); +dma_unmap_single (priv->device, rx_ring->rx_skbuff_dma[i], + dma_buf_sz,DMA_FROM_DEVICE ); +} +/** * init_tx_ring - init the TX descriptor ring * @dev: net device structure
@@ -456,7 +476,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,/* RX ring is not allcoated */ if (rx_ring =NULL ) {netdev_err (dev,"No memory for RX queue\n" ); - goto error; +return -ENOMEM ; }/* assign queue number */
@@ -468,23 +488,21 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, &rx_ring->dma_rx_phy, GFP_KERNEL);if (rx_ring->dma_rx =NULL ) - goto error; +return -ENOMEM ;/* allocate memory for RX skbuff array */ rx_ring->rx_skbuff_dma =kmalloc_array (rx_rsize,sizeof (dma_addr_t),GFP_KERNEL );if (!rx_ring->rx_skbuff_dma) { -dma_free_coherent (priv->device, - rx_rsize *sizeof (struct sxgbe_rx_norm_desc ), - rx_ring->dma_rx, rx_ring->dma_rx_phy); - goto error; + ret = -ENOMEM ; + goto err_free_dma_rx; } rx_ring->rx_skbuff =kmalloc_array (rx_rsize,sizeof (struct sk_buff *),GFP_KERNEL );if (!rx_ring->rx_skbuff) { -kfree (rx_ring->rx_skbuff_dma); - goto error; + ret = -ENOMEM ; + goto err_free_skbuff_dma; }/* initialise the buffers */
@@ -494,7 +512,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, ret =sxgbe_init_rx_buffers (dev, p, desc_index, bfsize, rx_ring);if (ret) - goto err_init_rx_buffers; + goto err_free_rx_buffers; }/* initalise counters */
@@ -504,11 +522,22 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,return 0 ; -err_init_rx_buffers: -while (--desc_index >=0 ) -free_rx_ring (priv->device, rx_ring, desc_index); -error: -return -ENOMEM ; +err_free_rx_buffers: +while (--desc_index >=0 ) { +struct sxgbe_rx_norm_desc *p; + + p = rx_ring->dma_rx + desc_index; +sxgbe_free_rx_buffers (dev, p, desc_index, bfsize, rx_ring); + } +kfree (rx_ring->rx_skbuff); +err_free_skbuff_dma: +kfree (rx_ring->rx_skbuff_dma); +err_free_dma_rx: +dma_free_coherent (priv->device, + rx_rsize *sizeof (struct sxgbe_rx_norm_desc ), + rx_ring->dma_rx, rx_ring->dma_rx_phy); + +return ret; }/** * free_tx_ring - free the TX descriptor ring
David Miller
maintainerRe: [patch] net: sxgbe: fix error handling in init_rx_ring()
From: Dan Carpenter <[email protected]>
Date: Thu, 5 Feb 2015 11:00:42 +0300
Quoted 7 lines
There are a couple bugs with the error handling in this function.
1) If we can't allocate "
rx_ring->rx_skbuff" then we should calldma_free_coherent()but we don't.
2)free_rx_ring()frees "rx_ring->rx_skbuff_dma" and "rx_ring->rx_skbuff" so calling it in a loop causes a double free.
Quoted 5 lines
Also it was a bit confusing how we sometimes freed things before doing the goto. I've cleaned it up so it does error handling in normal kernel style.
Signed-off-by Dan Carpenter <[email protected]>
Looks good, applied, thanks Dan.