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