[PATCH v2] fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region()
Sebastian Alba Vives <[email protected]> Fri, 3 Apr 2026 11:57:18 -0600
| Newsgroups | org.kernel.vger.linux-fpga,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Sebastian Josue Alba Vives <[email protected]> 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 <[email protected]> --- 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