The patch titled Subject: mm/dmapool.c: debug: prevent endless loop in case of corruption has been added to the -mm tree. Its filename is dmapool-debug-prevent-endless-loop-in-case-of-corruption.patch This patch should soon appear at http://ozlabs.org/~akpm/mmots/broken-out/dmapool-debug-prevent-endless-loop-in-case-of-corruption.patch and later at http://ozlabs.org/~akpm/mmotm/broken-out/dmapool-debug-prevent-endless-loop-in-case-of-corruption.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Tony Battersby <tonyb@xxxxxxxxxxxxxxx> Subject: mm/dmapool.c: debug: prevent endless loop in case of corruption Prevent a possible endless loop with DMAPOOL_DEBUG enabled if a buggy driver corrupts DMA pool memory. Link: http://lkml.kernel.org/r/9e65ec2e-5e22-4f65-7b92-ca2af0c555f3@xxxxxxxxxxxxxxx Signed-off-by: Tony Battersby <tonyb@xxxxxxxxxxxxxxx> Cc: Andy Shevchenko <andy.shevchenko@xxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: John Garry <john.garry@xxxxxxxxxx> Cc: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- mm/dmapool.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) --- a/mm/dmapool.c~dmapool-debug-prevent-endless-loop-in-case-of-corruption +++ a/mm/dmapool.c @@ -454,17 +454,39 @@ void dma_pool_free(struct dma_pool *pool { void *page_vaddr = vaddr - offset; unsigned int chain = page->dma_free_off; + unsigned int free_blks = 0; + while (chain < pool->allocation) { - if (chain != offset) { - chain = *(int *)(page_vaddr + chain); - continue; + if (unlikely(chain == offset)) { + spin_unlock_irqrestore(&pool->lock, flags); + dev_err(pool->dev, + "dma_pool_free %s, dma %pad already free\n", + pool->name, &dma); + return; } - spin_unlock_irqrestore(&pool->lock, flags); - dev_err(pool->dev, - "dma_pool_free %s, dma %pad already free\n", - pool->name, &dma); - return; + + /* + * A buggy driver could corrupt the freelist by + * use-after-free, buffer overflow, etc. Besides + * checking for corruption, this also prevents an + * endless loop in case corruption causes a circular + * loop in the freelist. + */ + if (unlikely(++free_blks + page->dma_in_use > + pool->blks_per_alloc)) { + freelist_corrupt: + spin_unlock_irqrestore(&pool->lock, flags); + dev_err(pool->dev, + "dma_pool_free %s, freelist corrupted\n", + pool->name); + return; + } + + chain = *(int *)(page_vaddr + chain); } + if (unlikely(free_blks + page->dma_in_use != + pool->blks_per_alloc)) + goto freelist_corrupt; } memset(vaddr, POOL_POISON_FREED, pool->size); #endif _ Patches currently in -mm which might be from tonyb@xxxxxxxxxxxxxxx are dmapool-fix-boundary-comparison.patch dmapool-remove-checks-for-dev-==-null.patch dmapool-cleanup-dma_pool_destroy.patch dmapool-improve-scalability-of-dma_pool_alloc.patch dmapool-rename-fields-in-dma_page.patch dmapool-improve-scalability-of-dma_pool_free.patch dmapool-cleanup-integer-types.patch dmapool-improve-accuracy-of-debug-statistics.patch dmapool-debug-prevent-endless-loop-in-case-of-corruption.patch