diff options
| -rw-r--r-- | drivers/vfio/vfio_iommu_type1.c | 45 |
1 files changed, 18 insertions, 27 deletions
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 6673e7be507f..0734fbe5b651 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c | |||
| @@ -524,7 +524,7 @@ unwind: | |||
| 524 | static int vfio_dma_do_map(struct vfio_iommu *iommu, | 524 | static int vfio_dma_do_map(struct vfio_iommu *iommu, |
| 525 | struct vfio_iommu_type1_dma_map *map) | 525 | struct vfio_iommu_type1_dma_map *map) |
| 526 | { | 526 | { |
| 527 | dma_addr_t end, iova; | 527 | dma_addr_t iova = map->iova; |
| 528 | unsigned long vaddr = map->vaddr; | 528 | unsigned long vaddr = map->vaddr; |
| 529 | size_t size = map->size; | 529 | size_t size = map->size; |
| 530 | long npage; | 530 | long npage; |
| @@ -533,39 +533,30 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 533 | struct vfio_dma *dma; | 533 | struct vfio_dma *dma; |
| 534 | unsigned long pfn; | 534 | unsigned long pfn; |
| 535 | 535 | ||
| 536 | end = map->iova + map->size; | 536 | /* Verify that none of our __u64 fields overflow */ |
| 537 | if (map->size != size || map->vaddr != vaddr || map->iova != iova) | ||
| 538 | return -EINVAL; | ||
| 537 | 539 | ||
| 538 | mask = ((uint64_t)1 << __ffs(vfio_pgsize_bitmap(iommu))) - 1; | 540 | mask = ((uint64_t)1 << __ffs(vfio_pgsize_bitmap(iommu))) - 1; |
| 539 | 541 | ||
| 542 | WARN_ON(mask & PAGE_MASK); | ||
| 543 | |||
| 540 | /* READ/WRITE from device perspective */ | 544 | /* READ/WRITE from device perspective */ |
| 541 | if (map->flags & VFIO_DMA_MAP_FLAG_WRITE) | 545 | if (map->flags & VFIO_DMA_MAP_FLAG_WRITE) |
| 542 | prot |= IOMMU_WRITE; | 546 | prot |= IOMMU_WRITE; |
| 543 | if (map->flags & VFIO_DMA_MAP_FLAG_READ) | 547 | if (map->flags & VFIO_DMA_MAP_FLAG_READ) |
| 544 | prot |= IOMMU_READ; | 548 | prot |= IOMMU_READ; |
| 545 | 549 | ||
| 546 | if (!prot) | 550 | if (!prot || !size || (size | iova | vaddr) & mask) |
| 547 | return -EINVAL; /* No READ/WRITE? */ | ||
| 548 | |||
| 549 | if (vaddr & mask) | ||
| 550 | return -EINVAL; | ||
| 551 | if (map->iova & mask) | ||
| 552 | return -EINVAL; | ||
| 553 | if (!map->size || map->size & mask) | ||
| 554 | return -EINVAL; | ||
| 555 | |||
| 556 | WARN_ON(mask & PAGE_MASK); | ||
| 557 | |||
| 558 | /* Don't allow IOVA wrap */ | ||
| 559 | if (end && end < map->iova) | ||
| 560 | return -EINVAL; | 551 | return -EINVAL; |
| 561 | 552 | ||
| 562 | /* Don't allow virtual address wrap */ | 553 | /* Don't allow IOVA or virtual address wrap */ |
| 563 | if (vaddr + map->size && vaddr + map->size < vaddr) | 554 | if (iova + size - 1 < iova || vaddr + size - 1 < vaddr) |
| 564 | return -EINVAL; | 555 | return -EINVAL; |
| 565 | 556 | ||
| 566 | mutex_lock(&iommu->lock); | 557 | mutex_lock(&iommu->lock); |
| 567 | 558 | ||
| 568 | if (vfio_find_dma(iommu, map->iova, map->size)) { | 559 | if (vfio_find_dma(iommu, iova, size)) { |
| 569 | mutex_unlock(&iommu->lock); | 560 | mutex_unlock(&iommu->lock); |
| 570 | return -EEXIST; | 561 | return -EEXIST; |
| 571 | } | 562 | } |
| @@ -576,17 +567,17 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 576 | return -ENOMEM; | 567 | return -ENOMEM; |
| 577 | } | 568 | } |
| 578 | 569 | ||
| 579 | dma->iova = map->iova; | 570 | dma->iova = iova; |
| 580 | dma->vaddr = map->vaddr; | 571 | dma->vaddr = vaddr; |
| 581 | dma->prot = prot; | 572 | dma->prot = prot; |
| 582 | 573 | ||
| 583 | /* Insert zero-sized and grow as we map chunks of it */ | 574 | /* Insert zero-sized and grow as we map chunks of it */ |
| 584 | vfio_link_dma(iommu, dma); | 575 | vfio_link_dma(iommu, dma); |
| 585 | 576 | ||
| 586 | for (iova = map->iova; iova < end; iova += size, vaddr += size) { | 577 | while (size) { |
| 587 | /* Pin a contiguous chunk of memory */ | 578 | /* Pin a contiguous chunk of memory */ |
| 588 | npage = vfio_pin_pages(vaddr, (end - iova) >> PAGE_SHIFT, | 579 | npage = vfio_pin_pages(vaddr + dma->size, |
| 589 | prot, &pfn); | 580 | size >> PAGE_SHIFT, prot, &pfn); |
| 590 | if (npage <= 0) { | 581 | if (npage <= 0) { |
| 591 | WARN_ON(!npage); | 582 | WARN_ON(!npage); |
| 592 | ret = (int)npage; | 583 | ret = (int)npage; |
| @@ -594,14 +585,14 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, | |||
| 594 | } | 585 | } |
| 595 | 586 | ||
| 596 | /* Map it! */ | 587 | /* Map it! */ |
| 597 | ret = vfio_iommu_map(iommu, iova, pfn, npage, prot); | 588 | ret = vfio_iommu_map(iommu, iova + dma->size, pfn, npage, prot); |
| 598 | if (ret) { | 589 | if (ret) { |
| 599 | vfio_unpin_pages(pfn, npage, prot, true); | 590 | vfio_unpin_pages(pfn, npage, prot, true); |
| 600 | break; | 591 | break; |
| 601 | } | 592 | } |
| 602 | 593 | ||
| 603 | size = npage << PAGE_SHIFT; | 594 | size -= npage << PAGE_SHIFT; |
| 604 | dma->size += size; | 595 | dma->size += npage << PAGE_SHIFT; |
| 605 | } | 596 | } |
| 606 | 597 | ||
| 607 | if (ret) | 598 | if (ret) |
