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

Sebastian Alba Vives posted 1 patch 3 days, 16 hours ago
drivers/fpga/dfl-afu-dma-region.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
[PATCH v2] fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region()
Posted by Sebastian Alba Vives 3 days, 16 hours ago
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
Re: [PATCH v2] fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region()
Posted by Greg KH 3 days, 3 hours ago
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