b43: Fix possible NULL pointer dereference in DMA code

This fixes a possible NULL pointer dereference in an error path of the
DMA allocation error checking code. This is also necessary for a future
DMA API change that is on its way into the mainline kernel that adds
an additional dev parameter to dma_mapping_error().

This patch moves the whole struct b43_dmaring struct initialization
right before any DMA allocation operation.

Reported-by: Miles Lane <miles.lane@gmail.com>
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Michael Buesch 2008-06-12 11:58:56 +02:00 committed by John W. Linville
parent 051c256f67
commit 028118a5f0
1 changed files with 46 additions and 47 deletions

View File

@ -795,66 +795,23 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
{
struct b43_dmaring *ring;
int err;
int nr_slots;
dma_addr_t dma_test;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
goto out;
ring->type = type;
nr_slots = B43_RXRING_SLOTS;
ring->nr_slots = B43_RXRING_SLOTS;
if (for_tx)
nr_slots = B43_TXRING_SLOTS;
ring->nr_slots = B43_TXRING_SLOTS;
ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta),
ring->meta = kcalloc(ring->nr_slots, sizeof(struct b43_dmadesc_meta),
GFP_KERNEL);
if (!ring->meta)
goto err_kfree_ring;
if (for_tx) {
ring->txhdr_cache = kcalloc(nr_slots,
b43_txhdr_size(dev),
GFP_KERNEL);
if (!ring->txhdr_cache)
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
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)
goto err_kfree_meta;
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
b43err(dev->wl,
"TXHDR DMA allocation failed\n");
goto err_kfree_txhdr_cache;
}
}
dma_unmap_single(dev->dev->dma_dev,
dma_test, b43_txhdr_size(dev),
DMA_TO_DEVICE);
}
ring->type = type;
ring->dev = dev;
ring->nr_slots = nr_slots;
ring->mmio_base = b43_dmacontroller_base(type, controller_index);
ring->index = controller_index;
if (type == B43_DMA_64BIT)
@ -879,6 +836,48 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
ring->last_injected_overflow = jiffies;
#endif
if (for_tx) {
ring->txhdr_cache = kcalloc(ring->nr_slots,
b43_txhdr_size(dev),
GFP_KERNEL);
if (!ring->txhdr_cache)
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
/* ugh realloc */
kfree(ring->txhdr_cache);
ring->txhdr_cache = kcalloc(ring->nr_slots,
b43_txhdr_size(dev),
GFP_KERNEL | GFP_DMA);
if (!ring->txhdr_cache)
goto err_kfree_meta;
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
b43err(dev->wl,
"TXHDR DMA allocation failed\n");
goto err_kfree_txhdr_cache;
}
}
dma_unmap_single(dev->dev->dma_dev,
dma_test, b43_txhdr_size(dev),
DMA_TO_DEVICE);
}
err = alloc_ringmemory(ring);
if (err)
goto err_kfree_txhdr_cache;