[PATCH v2] fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region()

From: Sebastian Alba Vives

Date: Fri Apr 03 2026 - 14:02:35 EST


From: Sebastian Josue Alba Vives <sebasjosue84@xxxxxxxxx>

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@xxxxxxxxx>
---
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