summaryrefslogtreecommitdiff
path: root/drivers/iommu
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-06-30 06:57:27 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2023-06-30 06:57:27 +0300
commit31929ae00890d921618b0b449722dcdf4a4416cc (patch)
treeae6e4741e16527c82cb491ba4cd5b26af90ff6d6 /drivers/iommu
parentd35ac6ac0e80e55bcea79af18d935f19a3e8554c (diff)
parentdbe245cdf5189e88d680379ed13901356628b650 (diff)
downloadlinux-31929ae00890d921618b0b449722dcdf4a4416cc.tar.xz
Merge tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd
Pull iommufd updates from Jason Gunthorpe: "Just two syzkaller fixes, both for the same basic issue: using the area pointer during an access forced unmap while the locks protecting it were let go" * tag 'for-linus-iommufd' of git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd: iommufd: Call iopt_area_contig_done() under the lock iommufd: Do not access the area pointer after unlocking
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/iommufd/device.c2
-rw-r--r--drivers/iommu/iommufd/io_pagetable.c14
2 files changed, 12 insertions, 4 deletions
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 4f9b2142274c..29d05663d4d1 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -553,8 +553,8 @@ void iommufd_access_unpin_pages(struct iommufd_access *access,
iopt_area_iova_to_index(
area,
min(last_iova, iopt_area_last_iova(area))));
- up_read(&iopt->iova_rwsem);
WARN_ON(!iopt_area_contig_done(&iter));
+ up_read(&iopt->iova_rwsem);
}
EXPORT_SYMBOL_NS_GPL(iommufd_access_unpin_pages, IOMMUFD);
diff --git a/drivers/iommu/iommufd/io_pagetable.c b/drivers/iommu/iommufd/io_pagetable.c
index e0ae72b9e67f..724c4c574241 100644
--- a/drivers/iommu/iommufd/io_pagetable.c
+++ b/drivers/iommu/iommufd/io_pagetable.c
@@ -458,6 +458,7 @@ static int iopt_unmap_iova_range(struct io_pagetable *iopt, unsigned long start,
{
struct iopt_area *area;
unsigned long unmapped_bytes = 0;
+ unsigned int tries = 0;
int rc = -ENOENT;
/*
@@ -484,19 +485,26 @@ again:
goto out_unlock_iova;
}
+ if (area_first != start)
+ tries = 0;
+
/*
* num_accesses writers must hold the iova_rwsem too, so we can
* safely read it under the write side of the iovam_rwsem
* without the pages->mutex.
*/
if (area->num_accesses) {
+ size_t length = iopt_area_length(area);
+
start = area_first;
area->prevent_access = true;
up_write(&iopt->iova_rwsem);
up_read(&iopt->domains_rwsem);
- iommufd_access_notify_unmap(iopt, area_first,
- iopt_area_length(area));
- if (WARN_ON(READ_ONCE(area->num_accesses)))
+
+ iommufd_access_notify_unmap(iopt, area_first, length);
+ /* Something is not responding to unmap requests. */
+ tries++;
+ if (WARN_ON(tries > 100))
return -EDEADLOCK;
goto again;
}