| From 2d0b1550865ff3ca459693de780e714644445615 Mon Sep 17 00:00:00 2001 |
| From: Marc Zyngier <maz@kernel.org> |
| Date: Wed, 4 Mar 2020 11:11:17 +0000 |
| Subject: [PATCH] iommu/dma: Fix MSI reservation allocation |
| |
| commit 65ac74f1de3334852fb7d9b1b430fa5a06524276 upstream. |
| |
| The way cookie_init_hw_msi_region() allocates the iommu_dma_msi_page |
| structures doesn't match the way iommu_put_dma_cookie() frees them. |
| |
| The former performs a single allocation of all the required structures, |
| while the latter tries to free them one at a time. It doesn't quite |
| work for the main use case (the GICv3 ITS where the range is 64kB) |
| when the base granule size is 4kB. |
| |
| This leads to a nice slab corruption on teardown, which is easily |
| observable by simply creating a VF on a SRIOV-capable device, and |
| tearing it down immediately (no need to even make use of it). |
| Fortunately, this only affects systems where the ITS isn't translated |
| by the SMMU, which are both rare and non-standard. |
| |
| Fix it by allocating iommu_dma_msi_page structures one at a time. |
| |
| Fixes: 7c1b058c8b5a3 ("iommu/dma: Handle IOMMU API reserved regions") |
| Signed-off-by: Marc Zyngier <maz@kernel.org> |
| Reviewed-by: Eric Auger <eric.auger@redhat.com> |
| Cc: Robin Murphy <robin.murphy@arm.com> |
| Cc: Joerg Roedel <jroedel@suse.de> |
| Cc: Will Deacon <will@kernel.org> |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Robin Murphy <robin.murphy@arm.com> |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c |
| index 1b47276c45a9..84d7cc0ee566 100644 |
| --- a/drivers/iommu/dma-iommu.c |
| +++ b/drivers/iommu/dma-iommu.c |
| @@ -179,15 +179,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie, |
| start -= iova_offset(iovad, start); |
| num_pages = iova_align(iovad, end - start) >> iova_shift(iovad); |
| |
| - msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL); |
| - if (!msi_page) |
| - return -ENOMEM; |
| - |
| for (i = 0; i < num_pages; i++) { |
| - msi_page[i].phys = start; |
| - msi_page[i].iova = start; |
| - INIT_LIST_HEAD(&msi_page[i].list); |
| - list_add(&msi_page[i].list, &cookie->msi_page_list); |
| + msi_page = kmalloc(sizeof(*msi_page), GFP_KERNEL); |
| + if (!msi_page) |
| + return -ENOMEM; |
| + |
| + msi_page->phys = start; |
| + msi_page->iova = start; |
| + INIT_LIST_HEAD(&msi_page->list); |
| + list_add(&msi_page->list, &cookie->msi_page_list); |
| start += iovad->granule; |
| } |
| |
| -- |
| 2.7.4 |
| |