Re: [PATCH v3 9/15] iommufd: Data structure to provide IOVA to PFN mapping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux