Skip to content

Commit 6012379

Browse files
Alex Mastroawilliam
authored andcommitted
vfio/type1: sanitize for overflow using check_*_overflow()
Adopt check_*_overflow() functions to clearly express overflow check intent. Tested-by: Alejandro Jimenez <[email protected]> Fixes: 73fa0d1 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Alejandro Jimenez <[email protected]> Signed-off-by: Alex Mastro <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent dcb6fa3 commit 6012379

File tree

1 file changed

+63
-23
lines changed

1 file changed

+63
-23
lines changed

drivers/vfio/vfio_iommu_type1.c

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <linux/workqueue.h>
3939
#include <linux/notifier.h>
4040
#include <linux/mm_inline.h>
41+
#include <linux/overflow.h>
4142
#include "vfio.h"
4243

4344
#define DRIVER_VERSION "0.2"
@@ -182,7 +183,7 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
182183
}
183184

184185
static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu,
185-
dma_addr_t start, u64 size)
186+
dma_addr_t start, size_t size)
186187
{
187188
struct rb_node *res = NULL;
188189
struct rb_node *node = iommu->dma_list.rb_node;
@@ -895,14 +896,20 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
895896
unsigned long remote_vaddr;
896897
struct vfio_dma *dma;
897898
bool do_accounting;
899+
dma_addr_t iova_end;
900+
size_t iova_size;
898901

899-
if (!iommu || !pages)
902+
if (!iommu || !pages || npage <= 0)
900903
return -EINVAL;
901904

902905
/* Supported for v2 version only */
903906
if (!iommu->v2)
904907
return -EACCES;
905908

909+
if (check_mul_overflow(npage, PAGE_SIZE, &iova_size) ||
910+
check_add_overflow(user_iova, iova_size - 1, &iova_end))
911+
return -EOVERFLOW;
912+
906913
mutex_lock(&iommu->lock);
907914

908915
if (WARN_ONCE(iommu->vaddr_invalid_count,
@@ -1008,12 +1015,21 @@ static void vfio_iommu_type1_unpin_pages(void *iommu_data,
10081015
{
10091016
struct vfio_iommu *iommu = iommu_data;
10101017
bool do_accounting;
1018+
dma_addr_t iova_end;
1019+
size_t iova_size;
10111020
int i;
10121021

10131022
/* Supported for v2 version only */
10141023
if (WARN_ON(!iommu->v2))
10151024
return;
10161025

1026+
if (WARN_ON(npage <= 0))
1027+
return;
1028+
1029+
if (WARN_ON(check_mul_overflow(npage, PAGE_SIZE, &iova_size) ||
1030+
check_add_overflow(user_iova, iova_size - 1, &iova_end)))
1031+
return;
1032+
10171033
mutex_lock(&iommu->lock);
10181034

10191035
do_accounting = list_empty(&iommu->domain_list);
@@ -1374,7 +1390,8 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
13741390
int ret = -EINVAL, retries = 0;
13751391
unsigned long pgshift;
13761392
dma_addr_t iova = unmap->iova;
1377-
u64 size = unmap->size;
1393+
dma_addr_t iova_end;
1394+
size_t size = unmap->size;
13781395
bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL;
13791396
bool invalidate_vaddr = unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR;
13801397
struct rb_node *n, *first_n;
@@ -1387,6 +1404,11 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
13871404
goto unlock;
13881405
}
13891406

1407+
if (iova != unmap->iova || size != unmap->size) {
1408+
ret = -EOVERFLOW;
1409+
goto unlock;
1410+
}
1411+
13901412
pgshift = __ffs(iommu->pgsize_bitmap);
13911413
pgsize = (size_t)1 << pgshift;
13921414

@@ -1396,10 +1418,15 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
13961418
if (unmap_all) {
13971419
if (iova || size)
13981420
goto unlock;
1399-
size = U64_MAX;
1400-
} else if (!size || size & (pgsize - 1) ||
1401-
iova + size - 1 < iova || size > SIZE_MAX) {
1402-
goto unlock;
1421+
size = SIZE_MAX;
1422+
} else {
1423+
if (!size || size & (pgsize - 1))
1424+
goto unlock;
1425+
1426+
if (check_add_overflow(iova, size - 1, &iova_end)) {
1427+
ret = -EOVERFLOW;
1428+
goto unlock;
1429+
}
14031430
}
14041431

14051432
/* When dirty tracking is enabled, allow only min supported pgsize */
@@ -1446,7 +1473,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
14461473
if (dma && dma->iova != iova)
14471474
goto unlock;
14481475

1449-
dma = vfio_find_dma(iommu, iova + size - 1, 0);
1476+
dma = vfio_find_dma(iommu, iova_end, 0);
14501477
if (dma && dma->iova + dma->size != iova + size)
14511478
goto unlock;
14521479
}
@@ -1648,16 +1675,25 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
16481675
{
16491676
bool set_vaddr = map->flags & VFIO_DMA_MAP_FLAG_VADDR;
16501677
dma_addr_t iova = map->iova;
1678+
dma_addr_t iova_end;
16511679
unsigned long vaddr = map->vaddr;
1680+
unsigned long vaddr_end;
16521681
size_t size = map->size;
16531682
int ret = 0, prot = 0;
16541683
size_t pgsize;
16551684
struct vfio_dma *dma;
16561685

16571686
/* Verify that none of our __u64 fields overflow */
16581687
if (map->size != size || map->vaddr != vaddr || map->iova != iova)
1688+
return -EOVERFLOW;
1689+
1690+
if (!size)
16591691
return -EINVAL;
16601692

1693+
if (check_add_overflow(iova, size - 1, &iova_end) ||
1694+
check_add_overflow(vaddr, size - 1, &vaddr_end))
1695+
return -EOVERFLOW;
1696+
16611697
/* READ/WRITE from device perspective */
16621698
if (map->flags & VFIO_DMA_MAP_FLAG_WRITE)
16631699
prot |= IOMMU_WRITE;
@@ -1673,13 +1709,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
16731709

16741710
WARN_ON((pgsize - 1) & PAGE_MASK);
16751711

1676-
if (!size || (size | iova | vaddr) & (pgsize - 1)) {
1677-
ret = -EINVAL;
1678-
goto out_unlock;
1679-
}
1680-
1681-
/* Don't allow IOVA or virtual address wrap */
1682-
if (iova + size - 1 < iova || vaddr + size - 1 < vaddr) {
1712+
if ((size | iova | vaddr) & (pgsize - 1)) {
16831713
ret = -EINVAL;
16841714
goto out_unlock;
16851715
}
@@ -1710,7 +1740,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
17101740
goto out_unlock;
17111741
}
17121742

1713-
if (!vfio_iommu_iova_dma_valid(iommu, iova, iova + size - 1)) {
1743+
if (!vfio_iommu_iova_dma_valid(iommu, iova, iova_end)) {
17141744
ret = -EINVAL;
17151745
goto out_unlock;
17161746
}
@@ -2977,7 +3007,8 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_iommu *iommu,
29773007
struct vfio_iommu_type1_dirty_bitmap_get range;
29783008
unsigned long pgshift;
29793009
size_t data_size = dirty.argsz - minsz;
2980-
size_t iommu_pgsize;
3010+
size_t size, iommu_pgsize;
3011+
dma_addr_t iova, iova_end;
29813012

29823013
if (!data_size || data_size < sizeof(range))
29833014
return -EINVAL;
@@ -2986,14 +3017,24 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_iommu *iommu,
29863017
sizeof(range)))
29873018
return -EFAULT;
29883019

2989-
if (range.iova + range.size < range.iova)
3020+
iova = range.iova;
3021+
size = range.size;
3022+
3023+
if (iova != range.iova || size != range.size)
3024+
return -EOVERFLOW;
3025+
3026+
if (!size)
29903027
return -EINVAL;
3028+
3029+
if (check_add_overflow(iova, size - 1, &iova_end))
3030+
return -EOVERFLOW;
3031+
29913032
if (!access_ok((void __user *)range.bitmap.data,
29923033
range.bitmap.size))
29933034
return -EINVAL;
29943035

29953036
pgshift = __ffs(range.bitmap.pgsize);
2996-
ret = verify_bitmap_size(range.size >> pgshift,
3037+
ret = verify_bitmap_size(size >> pgshift,
29973038
range.bitmap.size);
29983039
if (ret)
29993040
return ret;
@@ -3007,19 +3048,18 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_iommu *iommu,
30073048
ret = -EINVAL;
30083049
goto out_unlock;
30093050
}
3010-
if (range.iova & (iommu_pgsize - 1)) {
3051+
if (iova & (iommu_pgsize - 1)) {
30113052
ret = -EINVAL;
30123053
goto out_unlock;
30133054
}
3014-
if (!range.size || range.size & (iommu_pgsize - 1)) {
3055+
if (size & (iommu_pgsize - 1)) {
30153056
ret = -EINVAL;
30163057
goto out_unlock;
30173058
}
30183059

30193060
if (iommu->dirty_page_tracking)
30203061
ret = vfio_iova_dirty_bitmap(range.bitmap.data,
3021-
iommu, range.iova,
3022-
range.size,
3062+
iommu, iova, size,
30233063
range.bitmap.pgsize);
30243064
else
30253065
ret = -EINVAL;

0 commit comments

Comments
 (0)