versal_align_dma_buffer() rounds a misaligned pointer up with
ALIGN() and memmove()s the full payload there, writing up to
ARCH_DMA_MINALIGN-1 bytes past the end of the caller's buffer.

Allocate a separate cache-aligned bounce buffer via
malloc_cache_aligned() and memcpy() into it instead, propagating
-ENOMEM on allocation failure and freeing it after use.

A misaligned buffer larger than the available malloc pool now fails
cleanly with -ENOMEM instead of silently corrupting adjacent memory
as before an explicit, diagnosable failure is strictly preferable
to undefined behavior that previously went unnoticed only because the
caller's buffer happened to have trailing slack.

Fixes: 26e054c943a7 ("arm64: versal: fpga: Add PL bit stream load support")
Signed-off-by: Prasad Kummari <[email protected]>
---
 drivers/fpga/versalpl.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c
index 3cb56cc0dc9..3ad7a54baf1 100644
--- a/drivers/fpga/versalpl.c
+++ b/drivers/fpga/versalpl.c
@@ -10,14 +10,25 @@
 #include <versalpl.h>
 #include <zynqmp_firmware.h>
 #include <asm/cache.h>
+#include <linux/errno.h>
 
 static ulong versal_align_dma_buffer(ulong *buf, u32 len)
 {
        ulong *new_buf;
 
        if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) {
-               new_buf = (ulong *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN);
-               memmove(new_buf, buf, len);
+               /*
+                * ALIGN() rounds up, so an in-place forward memmove() would
+                * write past the end of the caller's buffer. Copy into a
+                * separately allocated, cache-aligned bounce buffer instead.
+                */
+               new_buf = malloc_cache_aligned(len);
+               if (!new_buf) {
+                       printf("%s: Failed to allocate aligned buffer\n",
+                              __func__);
+                       return 0;
+               }
+               memcpy(new_buf, buf, len);
                buf = new_buf;
        }
 
@@ -34,6 +45,9 @@ static int versal_load(xilinx_desc *desc, const void *buf, 
size_t bsize,
 
        bin_buf = versal_align_dma_buffer((ulong *)buf, bsize);
 
+       if (!bin_buf)
+               return -ENOMEM;
+
        debug("%s called!\n", __func__);
        flush_dcache_range(bin_buf, bin_buf + bsize);
 
@@ -51,6 +65,9 @@ static int versal_load(xilinx_desc *desc, const void *buf, 
size_t bsize,
        if (ret)
                printf("PL FPGA LOAD failed with err: 0x%08x\n", ret);
 
+       if (bin_buf != (ulong)buf)
+               free((void *)bin_buf);
+
        return ret;
 }
 
-- 
2.43.0

Reply via email to