]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dma: swiotlb: add KMSAN annotations to swiotlb_bounce()
authorShigeru Yoshida <syoshida@redhat.com>
Sun, 15 Mar 2026 08:27:49 +0000 (17:27 +0900)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 16 Mar 2026 10:29:20 +0000 (11:29 +0100)
When a device performs DMA to a bounce buffer, KMSAN is unaware of
the write and does not mark the data as initialized.  When
swiotlb_bounce() later copies the bounce buffer back to the original
buffer, memcpy propagates the uninitialized shadow to the original
buffer, causing false positive uninit-value reports.

Fix this by calling kmsan_unpoison_memory() on the bounce buffer
before copying it back in the DMA_FROM_DEVICE path, so that memcpy
naturally propagates initialized shadow to the destination.

Suggested-by: Alexander Potapenko <glider@google.com>
Link: https://lore.kernel.org/CAG_fn=WUGta-paG1BgsGRoAR+fmuCgh3xo=R3XdzOt_-DqSdHw@mail.gmail.com/
Fixes: 7ade4f10779c ("dma: kmsan: unpoison DMA mappings")
Signed-off-by: Shigeru Yoshida <syoshida@redhat.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/r/20260315082750.2375581-1-syoshida@redhat.com
kernel/dma/swiotlb.c

index d8e6f1d889d55dcc80bed7a4b5c9d71adc8e94eb..9fd73700ddcff28b54c43282fb008120a130eeef 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/io.h>
+#include <linux/kmsan-checks.h>
 #include <linux/iommu-helper.h>
 #include <linux/init.h>
 #include <linux/memblock.h>
@@ -901,10 +902,19 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
 
                        local_irq_save(flags);
                        page = pfn_to_page(pfn);
-                       if (dir == DMA_TO_DEVICE)
+                       if (dir == DMA_TO_DEVICE) {
+                               /*
+                                * Ideally, kmsan_check_highmem_page()
+                                * could be used here to detect infoleaks,
+                                * but callers may map uninitialized buffers
+                                * that will be written by the device,
+                                * causing false positives.
+                                */
                                memcpy_from_page(vaddr, page, offset, sz);
-                       else
+                       } else {
+                               kmsan_unpoison_memory(vaddr, sz);
                                memcpy_to_page(page, offset, vaddr, sz);
+                       }
                        local_irq_restore(flags);
 
                        size -= sz;
@@ -913,8 +923,15 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size
                        offset = 0;
                }
        } else if (dir == DMA_TO_DEVICE) {
+               /*
+                * Ideally, kmsan_check_memory() could be used here to detect
+                * infoleaks (uninitialized data being sent to device), but
+                * callers may map uninitialized buffers that will be written
+                * by the device, causing false positives.
+                */
                memcpy(vaddr, phys_to_virt(orig_addr), size);
        } else {
+               kmsan_unpoison_memory(vaddr, size);
                memcpy(phys_to_virt(orig_addr), vaddr, size);
        }
 }