From: David Stevens <[email protected]>

Only clear the padding bytes in bounce buffers, since syncing from the
original buffer already overwrites the non-padding bytes.

Signed-off-by: David Stevens <[email protected]>
---
 drivers/iommu/io-bounce-buffers.c | 64 +++++++++++++++++++++++++++++--
 drivers/iommu/io-buffer-manager.c |  7 +---
 2 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/io-bounce-buffers.c 
b/drivers/iommu/io-bounce-buffers.c
index c7c52a3f8bf7..ed05f593a195 100644
--- a/drivers/iommu/io-bounce-buffers.c
+++ b/drivers/iommu/io-bounce-buffers.c
@@ -296,14 +296,70 @@ bool io_bounce_buffers_unmap_sg(struct io_bounce_buffers 
*buffers,
                io_bounce_buffers_unmap_sg_sync, &args);
 }
 
+static void io_bounce_buffers_clear_padding(struct io_bounce_buffer_info *info,
+                                           size_t pad_hd_end,
+                                           size_t pad_tl_start)
+{
+       size_t idx, pad_hd_idx, pad_tl_idx, count;
+
+       count = info->size / PAGE_SIZE;
+       pad_hd_idx = pad_hd_end / PAGE_SIZE;
+       pad_tl_idx = pad_tl_start / PAGE_SIZE;
+
+       if (!IS_ALIGNED(pad_hd_end, PAGE_SIZE)) {
+               struct page *page = info->bounce_buffer[pad_hd_idx];
+               size_t len = offset_in_page(pad_hd_end);
+
+               memset_page(page, 0, 0, len);
+               arch_sync_dma_for_device(page_to_phys(page), 0, len);
+       }
+
+       if (!IS_ALIGNED(pad_tl_start, PAGE_SIZE)) {
+               size_t off = offset_in_page(pad_tl_start);
+               size_t len = PAGE_SIZE - off;
+               struct page *page = info->bounce_buffer[pad_tl_idx];
+
+               memset_page(page, off, 0, len);
+               arch_sync_dma_for_device(page_to_phys(page) + off, 0, len);
+
+               pad_tl_idx++;
+       }
+
+       idx = pad_hd_idx ? 0 : pad_tl_idx;
+       while (idx < count) {
+               struct page *page = info->bounce_buffer[idx++];
+
+               clear_highpage(page);
+               arch_sync_dma_for_device(page_to_phys(page), 0, PAGE_SIZE);
+               if (idx == pad_hd_idx)
+                       idx = pad_tl_idx;
+       }
+}
+
 static bool io_bounce_buffers_map_buffer(struct io_bounce_buffers *buffers,
                                         struct io_bounce_buffer_info *info,
-                                        int prot)
+                                        int prot, bool skiped_sync,
+                                        size_t offset, size_t orig_size)
 {
        unsigned int count = info->size >> PAGE_SHIFT;
        struct sg_table sgt;
        size_t mapped;
 
+       if (offset || offset + orig_size < info->size || skiped_sync) {
+               // Ensure that nothing is leaked to untrusted devices when
+               // mapping the buffer by clearing any part of the bounce buffer
+               // that wasn't already cleared by syncing.
+               size_t pad_hd_end, pad_tl_start;
+
+               if (skiped_sync) {
+                       pad_hd_end = pad_tl_start = 0;
+               } else {
+                       pad_hd_end = offset;
+                       pad_tl_start = offset + orig_size;
+               }
+               io_bounce_buffers_clear_padding(info, pad_hd_end, pad_tl_start);
+       }
+
        if (sg_alloc_table_from_pages(&sgt, info->bounce_buffer, count, 0,
                                      info->size, GFP_ATOMIC))
                return false;
@@ -338,7 +394,8 @@ bool io_bounce_buffers_map_page(struct io_bounce_buffers 
*buffers,
                io_bounce_buffers_do_sync(buffers, info.bounce_buffer, offset,
                                          page, offset, size, dir, prot, false);
 
-       if (!io_bounce_buffers_map_buffer(buffers, &info, prot)) {
+       if (!io_bounce_buffers_map_buffer(buffers, &info, prot, skip_cpu_sync,
+                                         offset, size)) {
                io_buffer_manager_release_buffer(&buffers->manager,
                                                 buffers->domain, info.iova,
                                                 false, NULL, NULL);
@@ -381,7 +438,8 @@ bool io_bounce_buffers_map_sg(struct io_bounce_buffers 
*buffers,
                                            info.bounce_buffer, dir, prot,
                                            false);
 
-       if (!io_bounce_buffers_map_buffer(buffers, &info, prot)) {
+       if (!io_bounce_buffers_map_buffer(buffers, &info, prot, skip_cpu_sync,
+                                         0, size)) {
                io_buffer_manager_release_buffer(&buffers->manager,
                                                 buffers->domain, info.iova,
                                                 false, NULL, NULL);
diff --git a/drivers/iommu/io-buffer-manager.c 
b/drivers/iommu/io-buffer-manager.c
index 79b9759da928..587584fdf26b 100644
--- a/drivers/iommu/io-buffer-manager.c
+++ b/drivers/iommu/io-buffer-manager.c
@@ -37,13 +37,10 @@ static struct page **io_buffer_manager_alloc_pages(int 
count, unsigned int nid)
        // pages first to make accessing the buffer cheaper.
        for (i = 0; i < count; i++) {
                pages[i] = alloc_pages_node(
-                       nid,
-                       GFP_ATOMIC | __GFP_ZERO | __GFP_NORETRY | __GFP_NOWARN,
-                       0);
+                       nid, GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN, 0);
                if (!pages[i]) {
                        pages[i] = alloc_pages_node(
-                               nid, GFP_ATOMIC | __GFP_ZERO | __GFP_HIGHMEM,
-                               0);
+                               nid, GFP_ATOMIC | __GFP_HIGHMEM, 0);
                        if (!pages[i]) {
                                io_buffer_manager_free_pages(pages, i);
                                return NULL;
-- 
2.32.0.605.g8dce9f2422-goog

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to