diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-06-30 06:57:27 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-06-30 06:57:27 +0300 |
commit | 31929ae00890d921618b0b449722dcdf4a4416cc (patch) | |
tree | ae6e4741e16527c82cb491ba4cd5b26af90ff6d6 /drivers/iommu | |
parent | d35ac6ac0e80e55bcea79af18d935f19a3e8554c (diff) | |
parent | dbe245cdf5189e88d680379ed13901356628b650 (diff) | |
download | linux-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.c | 2 | ||||
-rw-r--r-- | drivers/iommu/iommufd/io_pagetable.c | 14 |
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; } |