b43: Fix DMA mapping leakage
PATCH 1/1 b43: Fix DMA mapping leakage
This fixes a DMA mapping leakage in the case where we reject a DMA buffer because of its address.
Signed-off-by Michael Buesch <[email protected]>
Cc Christian Casteyde <[email protected]>
---
John, this is a fix for 2.6.25.
drivers/net/wireless/b43/dma.c +17 -10
@@ -512,34 +512,40 @@ static int b43_dmacontroller_tx_reset(streturn 0 ; }/* Check if a DMA mapping address is invalid. */ static bool b43_dma_mapping_error (struct b43_dmaring *ring,dma_addr_t addr, -size_t buffersize) +size_t buffersize,bool dma_to_device) {if (unlikely (dma_mapping_error (addr)))return 1 ;switch (ring->type) {case B43_DMA_30BIT :if ((u64 )addr + buffersize > (1ULL <<30 )) -return 1 ; + goto address_error;break ;case B43_DMA_32BIT :if ((u64 )addr + buffersize > (1ULL <<32 )) -return 1 ; + goto address_error;break ;case B43_DMA_64BIT :/* Currently we can't have addresses beyond * 64bit in the kernel. */ break ; }/* The address is OK. */ return 0 ; + +address_error: +/* We can't support this address. Unmap it again. */ +unmap_descbuffer (ring, addr, buffersize, dma_to_device); + +return 1 ; }static int setup_rx_descbuffer (struct b43_dmaring *ring,struct b43_dmadesc_generic *desc,struct b43_dmadesc_meta *meta,gfp_t gfp_flags) {
@@ -551,26 +557,26 @@ static int setup_rx_descbuffer(struct b4B43_WARN_ON (ring->tx); skb =__dev_alloc_skb (ring->rx_buffersize, gfp_flags);if (unlikely (!skb))return -ENOMEM ; dmaaddr =map_descbuffer (ring, skb->data, ring->rx_buffersize,0 ); -if (b43_dma_mapping_error (ring, dmaaddr, ring->rx_buffersize)) { +if (b43_dma_mapping_error (ring, dmaaddr, ring->rx_buffersize,0 )) {/* ugh. try to realloc in zone_dma */ gfp_flags |=GFP_DMA ;dev_kfree_skb_any (skb); skb =__dev_alloc_skb (ring->rx_buffersize, gfp_flags);if (unlikely (!skb))return -ENOMEM ; dmaaddr =map_descbuffer (ring, skb->data, ring->rx_buffersize,0 ); } -if (b43_dma_mapping_error (ring, dmaaddr, ring->rx_buffersize)) { +if (b43_dma_mapping_error (ring, dmaaddr, ring->rx_buffersize,0 )) {dev_kfree_skb_any (skb);return -EIO ; } meta->skb = skb; meta->dmaaddr = dmaaddr;
@@ -804,13 +810,14 @@ struct b43_dmaring *b43_setup_dmaring(st/* test for ability to dma to txhdr_cache */ dma_test =dma_map_single (dev->dev->dev, ring->txhdr_cache,b43_txhdr_size (dev),DMA_TO_DEVICE ); -if (b43_dma_mapping_error (ring, dma_test,b43_txhdr_size (dev))) { +if (b43_dma_mapping_error (ring, dma_test, +b43_txhdr_size (dev),1 )) {/* ugh realloc */ kfree (ring->txhdr_cache); ring->txhdr_cache =kcalloc (nr_slots,b43_txhdr_size (dev),GFP_KERNEL |GFP_DMA );if (!ring->txhdr_cache)
@@ -819,13 +826,13 @@ struct b43_dmaring *b43_setup_dmaring(st dma_test =dma_map_single (dev->dev->dev, ring->txhdr_cache,b43_txhdr_size (dev),DMA_TO_DEVICE );if (b43_dma_mapping_error (ring, dma_test, -b43_txhdr_size (dev))) +b43_txhdr_size (dev),1 )) goto err_kfree_txhdr_cache; }dma_unmap_single (dev->dev->dev, dma_test,b43_txhdr_size (dev),DMA_TO_DEVICE );
@@ -1120,13 +1127,13 @@ static int dma_tx_fragment(struct b43_dm ring->used_slots = old_used_slots;return err; } meta_hdr->dmaaddr =map_descbuffer (ring, (unsigned char *)header, hdrsize,1 ); -if (b43_dma_mapping_error (ring, meta_hdr->dmaaddr, hdrsize)) { +if (b43_dma_mapping_error (ring, meta_hdr->dmaaddr, hdrsize,1 )) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots;return -EIO ; } ops->fill_descriptor (ring, desc, meta_hdr->dmaaddr, hdrsize,1 ,0 ,0 );
@@ -1139,13 +1146,13 @@ static int dma_tx_fragment(struct b43_dmmemcpy (&meta->txstat.control, ctl,sizeof (*ctl)); meta->skb = skb; meta->is_last_fragment =1 ; meta->dmaaddr =map_descbuffer (ring, skb->data, skb->len,1 );/* create a bounce buffer in zone_dma on mapping failure. */ -if (b43_dma_mapping_error (ring, meta->dmaaddr, skb->len)) { +if (b43_dma_mapping_error (ring, meta->dmaaddr, skb->len,1 )) { bounce_skb =__dev_alloc_skb (skb->len,GFP_ATOMIC |GFP_DMA );if (!bounce_skb) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -ENOMEM ; goto out_unmap_hdr;
@@ -1153,13 +1160,13 @@ static int dma_tx_fragment(struct b43_dmmemcpy (skb_put (bounce_skb, skb->len), skb->data, skb->len);dev_kfree_skb_any (skb); skb = bounce_skb; meta->skb = skb; meta->dmaaddr =map_descbuffer (ring, skb->data, skb->len,1 ); -if (b43_dma_mapping_error (ring, meta->dmaaddr, skb->len)) { +if (b43_dma_mapping_error (ring, meta->dmaaddr, skb->len,1 )) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -EIO ; goto out_free_bounce; } }