On Tue, Oct 25, 2022 at 03:12:18PM -0300, Jason Gunthorpe wrote:
+/* All existing area's conform to an increased page size */ +static int iopt_check_iova_alignment(struct io_pagetable *iopt,
unsigned long new_iova_alignment)
+{
- struct iopt_area *area;
- lockdep_assert_held(&iopt->iova_rwsem);
- for (area = iopt_area_iter_first(iopt, 0, ULONG_MAX); area;
area = iopt_area_iter_next(area, 0, ULONG_MAX))
if ((iopt_area_iova(area) % new_iova_alignment) ||
(iopt_area_length(area) % new_iova_alignment))
return -EADDRINUSE;
While working on the last syzkaller bug I noticed this doesn't reject bad user VAs when doing an alignment upgrade, and the return code got botched during some refactoring:
@@ -801,14 +801,16 @@ static int iopt_fill_domain(struct io_pagetable *iopt, static int iopt_check_iova_alignment(struct io_pagetable *iopt, unsigned long new_iova_alignment) { + unsigned long align_mask = new_iova_alignment - 1; struct iopt_area *area;
lockdep_assert_held(&iopt->iova_rwsem);
for (area = iopt_area_iter_first(iopt, 0, ULONG_MAX); area; area = iopt_area_iter_next(area, 0, ULONG_MAX)) - if ((iopt_area_iova(area) % new_iova_alignment) || - (iopt_area_length(area) % new_iova_alignment)) + if ((iopt_area_iova(area) & align_mask) || + (iopt_area_length(area) & align_mask) || + (area->page_offset & align_mask)) return -EADDRINUSE; return 0; } @@ -891,7 +893,7 @@ int iopt_table_add_domain(struct io_pagetable *iopt, return rc; }
-static bool iopt_calculate_iova_alignment(struct io_pagetable *iopt) +static int iopt_calculate_iova_alignment(struct io_pagetable *iopt) { unsigned long new_iova_alignment; struct iommu_domain *domain; @@ -913,7 +915,7 @@ static bool iopt_calculate_iova_alignment(struct io_pagetable *iopt)
rc = iopt_check_iova_alignment(iopt, new_iova_alignment); if (rc) - return -EADDRINUSE; + return rc; } iopt->iova_alignment = new_iova_alignment; return 0;
And added a test to cover.
Jason