* [PATCH] Fixes a race in iopt_unmap_iova_range
@ 2026-04-06 22:00 Sina Hassani
2026-04-06 22:17 ` Jason Gunthorpe
0 siblings, 1 reply; 3+ messages in thread
From: Sina Hassani @ 2026-04-06 22:00 UTC (permalink / raw)
To: jgg
Cc: kevin.tian, joro, will, robin.murphy, iommu, linux-kernel,
Aaron Wisner, Sina Hassani, stable
Bug: iopt_unmap_iova_range releases the lock on iova_rwsem inside the loop
body when getting to the more expensive unmap operations. This is fine on
its own except the loop condition is based on the first area that matches
the unmap address range. If a concurrent call to map picks an area that was
unmapped in the previous iterations, this loop will try to mistakenly unmap
them.
How to reproduce: I was able to reproduce this by having one userspace
thread mapping buffers and passing them to another thread that maps
them. The problem easily shows up as ebusy errors if you use single page
mappings.
The fix: A simple fix that I implemented here is to advance the start
pointer after we unmap an area. That way we are only looking at the
IOVA range that is mapped and hence guaranteed to not have any overlaps
in each iteration.
Test: I tested this against the repro mentioned above and it works fine.
Cc: stable@vger.kernel.org
Signed-off-by: Sina Hassani <sina@openai.com>
---
drivers/iommu/iommufd/io_pagetable.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/iommu/iommufd/io_pagetable.c
b/drivers/iommu/iommufd/io_pagetable.c
index ee003bb2f647..965fa23df103 100644
--- a/drivers/iommu/iommufd/io_pagetable.c
+++ b/drivers/iommu/iommufd/io_pagetable.c
@@ -812,6 +812,7 @@ static int iopt_unmap_iova_range(struct
io_pagetable *iopt, unsigned long start,
iopt_put_pages(pages);
unmapped_bytes += area_last - area_first + 1;
+ start = area_last + 1;
down_write(&iopt->iova_rwsem);
}
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Fixes a race in iopt_unmap_iova_range
2026-04-06 22:00 [PATCH] Fixes a race in iopt_unmap_iova_range Sina Hassani
@ 2026-04-06 22:17 ` Jason Gunthorpe
2026-04-06 23:07 ` Sina Hassani
0 siblings, 1 reply; 3+ messages in thread
From: Jason Gunthorpe @ 2026-04-06 22:17 UTC (permalink / raw)
To: Sina Hassani
Cc: kevin.tian, joro, will, robin.murphy, iommu, linux-kernel,
Aaron Wisner, stable
On Mon, Apr 06, 2026 at 03:00:36PM -0700, Sina Hassani wrote:
> Bug: iopt_unmap_iova_range releases the lock on iova_rwsem inside the loop
> body when getting to the more expensive unmap operations. This is fine on
> its own except the loop condition is based on the first area that matches
> the unmap address range. If a concurrent call to map picks an area that was
> unmapped in the previous iterations, this loop will try to mistakenly unmap
> them.
Does this mean you are also using the automatic IOVA allocator?
It is certainly an error for userspace to be mapping to IOVA that is
under concurrent unmap.
> io_pagetable *iopt, unsigned long start,
> iopt_put_pages(pages);
>
> unmapped_bytes += area_last - area_first + 1;
> + start = area_last + 1;
This seems like a reasonable solution, but area_last + 1 can overflow
and that needs to be delt with too.
/* Do not reconsider things already unmapped in case of concurrent allocation */
if (area_last != last)
start = area_last + 1;
?
Jason
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Fixes a race in iopt_unmap_iova_range
2026-04-06 22:17 ` Jason Gunthorpe
@ 2026-04-06 23:07 ` Sina Hassani
0 siblings, 0 replies; 3+ messages in thread
From: Sina Hassani @ 2026-04-06 23:07 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: kevin.tian, joro, will, robin.murphy, iommu, linux-kernel,
Aaron Wisner, stable
On Mon, Apr 6, 2026 at 3:17 PM Jason Gunthorpe <jgg@ziepe.ca> wrote:
>
> On Mon, Apr 06, 2026 at 03:00:36PM -0700, Sina Hassani wrote:
> > Bug: iopt_unmap_iova_range releases the lock on iova_rwsem inside the loop
> > body when getting to the more expensive unmap operations. This is fine on
> > its own except the loop condition is based on the first area that matches
> > the unmap address range. If a concurrent call to map picks an area that was
> > unmapped in the previous iterations, this loop will try to mistakenly unmap
> > them.
>
> Does this mean you are also using the automatic IOVA allocator?
>
> It is certainly an error for userspace to be mapping to IOVA that is
> under concurrent unmap.
>
Correct.
> > io_pagetable *iopt, unsigned long start,
> > iopt_put_pages(pages);
> >
> > unmapped_bytes += area_last - area_first + 1;
> > + start = area_last + 1;
>
> This seems like a reasonable solution, but area_last + 1 can overflow
> and that needs to be delt with too.
>
Good point, done. I sent you a v2 patch.
> /* Do not reconsider things already unmapped in case of concurrent allocation */
> if (area_last != last)
> start = area_last + 1;
>
> ?
>
Done
> Jason
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-06 23:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-06 22:00 [PATCH] Fixes a race in iopt_unmap_iova_range Sina Hassani
2026-04-06 22:17 ` Jason Gunthorpe
2026-04-06 23:07 ` Sina Hassani
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®