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 <[email protected]>
---
 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);
-- 
2.43.0

Reply via email to