swiotlb: fix out-of-bounds TLB allocations with CONFIG_SWIOTLB_DYNAMIC
authorPetr Tesarik <petr.tesarik1@huawei-partners.com>
Wed, 8 Nov 2023 11:12:49 +0000 (12:12 +0100)
committerChristoph Hellwig <hch@lst.de>
Wed, 8 Nov 2023 15:27:05 +0000 (16:27 +0100)
Limit the free list length to the size of the IO TLB. Transient pool can be
smaller than IO_TLB_SEGSIZE, but the free list is initialized with the
assumption that the total number of slots is a multiple of IO_TLB_SEGSIZE.
As a result, swiotlb_area_find_slots() may allocate slots past the end of
a transient IO TLB buffer.

Reported-by: Niklas Schnelle <schnelle@linux.ibm.com>
Closes: https://lore.kernel.org/linux-iommu/104a8c8fedffd1ff8a2890983e2ec1c26bff6810.camel@linux.ibm.com/
Fixes: 79636caad361 ("swiotlb: if swiotlb is full, fall back to a transient memory pool")
Cc: stable@vger.kernel.org
Signed-off-by: Petr Tesarik <petr.tesarik1@huawei-partners.com>
Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
kernel/dma/swiotlb.c

index 71392c9fac1030f1d28db93121faa88a32aa48a6..33d942615be54ccf6ed616c50a9db499c99b6816 100644 (file)
@@ -283,7 +283,8 @@ static void swiotlb_init_io_tlb_pool(struct io_tlb_pool *mem, phys_addr_t start,
        }
 
        for (i = 0; i < mem->nslabs; i++) {
-               mem->slots[i].list = IO_TLB_SEGSIZE - io_tlb_offset(i);
+               mem->slots[i].list = min(IO_TLB_SEGSIZE - io_tlb_offset(i),
+                                        mem->nslabs - i);
                mem->slots[i].orig_addr = INVALID_PHYS_ADDR;
                mem->slots[i].alloc_size = 0;
        }