If converting one of the allocated pages to shared memory fails, the cleanup path attempts to convert every page back to private memory. Pages after the failed page have not been converted yet, so attempting to convert them back can fail and cause otherwise reusable memory to be leaked.
Count the pages converted successfully and only convert those and the failed allocation back during cleanup. If converting the failed allocation back succeeds it can be freed safely; otherwise it is leaked because its state is unknown. Allocations that were not converted can be freed directly.
Fixes: 78b30c50a7ac ("dma-buf: heaps: system: add system_cc_shared heap for explicitly shared memory") Signed-off-by: Steven Price steven.price@arm.com --- drivers/dma-buf/heaps/system_heap.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index f14930904089..8d3ffeb64e00 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -418,6 +418,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap, struct scatterlist *sg; struct list_head pages; struct page *page, *tmp_page; + int nr_decrypted = 0; int i, ret = -ENOMEM;
buffer = kzalloc_obj(*buffer); @@ -472,6 +473,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap, goto free_pages;
clear_pages(page_address(page), 1 << compound_order(page)); + nr_decrypted++; } }
@@ -496,9 +498,11 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap, * Intentionally leak pages that cannot be re-encrypted * to prevent shared memory from being reused. */ - if (cc_shared_buffer(buffer) && - system_heap_set_page_encrypted(p)) - continue; + if (cc_shared_buffer(buffer)) { + if (i <= nr_decrypted && + system_heap_set_page_encrypted(p)) + continue; + } __free_pages(p, compound_order(p)); } sg_free_table(table);