[PATCH] vhost/vdpa: reject overflowing PA map page counts

From: Yousef Alhouseen

Date: Wed Jun 24 2026 - 15:07:34 EST


vhost_vdpa_pa_map() adds the IOVA page offset to the user-controlled map
size before computing the number of pages to pin. If that addition wraps,
the code can pin and map fewer pages than the requested IOTLB range.

Reject sizes that overflow the page-count calculation. Also make the
memlock check subtraction-based so a large page count cannot wrap the
pinned page total.

Signed-off-by: Yousef Alhouseen <alhouseenyousef@xxxxxxxxx>
---
drivers/vhost/vdpa.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index ac55275fa..090cb8693 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -1102,6 +1102,8 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
unsigned int gup_flags = FOLL_LONGTERM;
unsigned long npages, cur_base, map_pfn, last_pfn = 0;
unsigned long lock_limit, sz2pin, nchunks, i;
+ unsigned long page_offset;
+ u64 pinned_vm;
u64 start = iova;
long pinned;
int ret = 0;
@@ -1114,7 +1116,12 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
if (perm & VHOST_ACCESS_WO)
gup_flags |= FOLL_WRITE;

- npages = PFN_UP(size + (iova & ~PAGE_MASK));
+ page_offset = iova & ~PAGE_MASK;
+ if (size > ULONG_MAX - page_offset) {
+ ret = -EINVAL;
+ goto free;
+ }
+ npages = PFN_UP(size + page_offset);
if (!npages) {
ret = -EINVAL;
goto free;
@@ -1123,7 +1130,8 @@ static int vhost_vdpa_pa_map(struct vhost_vdpa *v,
mmap_read_lock(dev->mm);

lock_limit = PFN_DOWN(rlimit(RLIMIT_MEMLOCK));
- if (npages + atomic64_read(&dev->mm->pinned_vm) > lock_limit) {
+ pinned_vm = atomic64_read(&dev->mm->pinned_vm);
+ if (npages > lock_limit || pinned_vm > lock_limit - npages) {
ret = -ENOMEM;
goto unlock;
}
--
2.54.0