drivers/fpga/dfl-afu-dma-region.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
From: Sebastian Josue Alba Vives <sebasjosue84@gmail.com>
region->length comes from userspace via the DFL_FPGA_PORT_DMA_MAP ioctl
as a __u64 value. While the function checks for page alignment and
address overflow, there is no upper bound on the length value. When
length >> PAGE_SHIFT exceeds INT_MAX, the downstream call to
pin_user_pages_fast() (which takes int nr_pages) receives a truncated
value.
Add the length validation alongside the existing input checks in
afu_dma_map_region(), where all userspace arguments are validated
before being passed deeper into the call chain.
Signed-off-by: Sebastian Alba Vives <sebasjosue84@gmail.com>
---
Changes in v2:
- Move validation from afu_dma_pin_pages() to afu_dma_map_region()
to validate at the ioctl entry point as suggested by Greg KH
- Keep npages as int in afu_dma_pin_pages() (now always safe)
drivers/fpga/dfl-afu-dma-region.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c
index 0d1f973..7f434a9 100644
--- a/drivers/fpga/dfl-afu-dma-region.c
+++ b/drivers/fpga/dfl-afu-dma-region.c
@@ -34,13 +34,10 @@ void afu_dma_region_init(struct dfl_feature_dev_data *fdata)
static int afu_dma_pin_pages(struct dfl_feature_dev_data *fdata,
struct dfl_afu_dma_region *region)
{
- unsigned long npages = region->length >> PAGE_SHIFT;
+ int npages = region->length >> PAGE_SHIFT;
struct device *dev = &fdata->dev->dev;
int ret, pinned;
- if (npages > INT_MAX)
- return -EINVAL;
-
ret = account_locked_vm(current->mm, npages, true);
if (ret)
return ret;
@@ -319,6 +316,10 @@ int afu_dma_map_region(struct dfl_feature_dev_data *fdata,
if (user_addr + length < user_addr)
return -EINVAL;
+ /* Ensure length does not exceed what pin_user_pages_fast() can handle */
+ if (length >> PAGE_SHIFT > INT_MAX)
+ return -EINVAL;
+
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
--
2.43.0
On Fri, Apr 03, 2026 at 11:57:18AM -0600, Sebastian Alba Vives wrote: > From: Sebastian Josue Alba Vives <sebasjosue84@gmail.com> > > region->length comes from userspace via the DFL_FPGA_PORT_DMA_MAP ioctl > as a __u64 value. While the function checks for page alignment and > address overflow, there is no upper bound on the length value. When > length >> PAGE_SHIFT exceeds INT_MAX, the downstream call to > pin_user_pages_fast() (which takes int nr_pages) receives a truncated > value. > > Add the length validation alongside the existing input checks in > afu_dma_map_region(), where all userspace arguments are validated > before being passed deeper into the call chain. > > Signed-off-by: Sebastian Alba Vives <sebasjosue84@gmail.com> > --- > Changes in v2: > - Move validation from afu_dma_pin_pages() to afu_dma_map_region() > to validate at the ioctl entry point as suggested by Greg KH This isn't the ioctl entry point, why not put it in afu_ioctl_dma_map() with the other checks? thanks, greg k-h
© 2016 - 2026 Red Hat, Inc.