]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommufd: Do not allow creating areas without READ or WRITE
authorJason Gunthorpe <jgg@nvidia.com>
Thu, 22 Aug 2024 14:45:54 +0000 (11:45 -0300)
committerJoerg Roedel <jroedel@suse.de>
Mon, 26 Aug 2024 07:16:13 +0000 (09:16 +0200)
This results in passing 0 or just IOMMU_CACHE to iommu_map(). Most of
the page table formats don't like this:

  amdv1 - -EINVAL
  armv7s - returns 0, doesn't update mapped
  arm-lpae - returns 0 doesn't update mapped
  dart - returns 0, doesn't update mapped
  VT-D - returns -EINVAL

Unfortunately the three formats that return 0 cause serious problems:

 - Returning ret = but not uppdating mapped from domain->map_pages()
   causes an infinite loop in __iommu_map()

 - Not writing ioptes means that VFIO/iommufd have no way to recover them
   and we will have memory leaks and worse during unmap

Since almost nothing can support this, and it is a useless thing to do,
block it early in iommufd.

Cc: stable@kernel.org
Fixes: aad37e71d5c4 ("iommufd: IOCTLs for the io_pagetable")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/1-v1-1211e1294c27+4b1-iommu_no_prot_jgg@nvidia.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/iommufd/ioas.c
tools/testing/selftests/iommu/iommufd.c

index 74224827654815fbe16ea0da18128ca470c15ffd..157a89b993e438b5558af501e209a9928ac42236 100644 (file)
@@ -213,6 +213,10 @@ int iommufd_ioas_map(struct iommufd_ucmd *ucmd)
        if (cmd->iova >= ULONG_MAX || cmd->length >= ULONG_MAX)
                return -EOVERFLOW;
 
+       if (!(cmd->flags &
+             (IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE)))
+               return -EINVAL;
+
        ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id);
        if (IS_ERR(ioas))
                return PTR_ERR(ioas);
@@ -253,6 +257,10 @@ int iommufd_ioas_copy(struct iommufd_ucmd *ucmd)
            cmd->dst_iova >= ULONG_MAX)
                return -EOVERFLOW;
 
+       if (!(cmd->flags &
+             (IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE)))
+               return -EINVAL;
+
        src_ioas = iommufd_get_ioas(ucmd->ictx, cmd->src_ioas_id);
        if (IS_ERR(src_ioas))
                return PTR_ERR(src_ioas);
index 6343f4053bd46ef5d8fbcf45d520b82d9e5a6c08..4927b9add5add913c955d2f63b884dd0df81ffcb 100644 (file)
@@ -825,7 +825,7 @@ TEST_F(iommufd_ioas, copy_area)
 {
        struct iommu_ioas_copy copy_cmd = {
                .size = sizeof(copy_cmd),
-               .flags = IOMMU_IOAS_MAP_FIXED_IOVA,
+               .flags = IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE,
                .dst_ioas_id = self->ioas_id,
                .src_ioas_id = self->ioas_id,
                .length = PAGE_SIZE,
@@ -1318,7 +1318,7 @@ TEST_F(iommufd_ioas, copy_sweep)
 {
        struct iommu_ioas_copy copy_cmd = {
                .size = sizeof(copy_cmd),
-               .flags = IOMMU_IOAS_MAP_FIXED_IOVA,
+               .flags = IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE,
                .src_ioas_id = self->ioas_id,
                .dst_iova = MOCK_APERTURE_START,
                .length = MOCK_PAGE_SIZE,
@@ -1608,7 +1608,7 @@ TEST_F(iommufd_mock_domain, user_copy)
        };
        struct iommu_ioas_copy copy_cmd = {
                .size = sizeof(copy_cmd),
-               .flags = IOMMU_IOAS_MAP_FIXED_IOVA,
+               .flags = IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE,
                .dst_ioas_id = self->ioas_id,
                .dst_iova = MOCK_APERTURE_START,
                .length = BUFFER_SIZE,