Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ffa9256a authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

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: default avatarMichael Buesch <mb@bu3sch.de>
Cc: Christian Casteyde <casteyde.christian@free.fr>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c83dbf68
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -560,7 +560,7 @@ static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
/* 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;
@@ -568,11 +568,11 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
	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
@@ -582,6 +582,12 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,

	/* 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,
@@ -599,7 +605,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
	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;

@@ -612,7 +618,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
					 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;
	}
@@ -852,7 +858,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
					  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,
@@ -867,7 +874,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *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;
		}

@@ -1189,7 +1196,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,

	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;
@@ -1208,7 +1215,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,

	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;
@@ -1222,7 +1229,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
		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;