[PATCH] media: coda: validate firmware payload bounds

From: Pengpeng Hou

Date: Mon Jul 06 2026 - 06:22:42 EST


coda_copy_firmware() accepts firmware images with an optional Freescale
header and then copies or reorders the payload.

Track the payload length after skipping the optional header. Reject
malformed native-order firmware payloads, and propagate the error so
hardware initialization does not continue with an invalid code buffer.

Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>
---
.../platform/chips-media/coda/coda-common.c | 43 ++++++++++++++-----
1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c
index be37ea568bfe..357bd9cdbfc6 100644
--- a/drivers/media/platform/chips-media/coda/coda-common.c
+++ b/drivers/media/platform/chips-media/coda/coda-common.c
@@ -2927,36 +2927,57 @@ static int coda_register_device(struct coda_dev *dev, int i)
return ret;
}

-static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf,
- size_t size)
+static int coda_copy_firmware(struct coda_dev *dev, const u8 * const buf,
+ size_t size)
{
- u32 *src = (u32 *)buf;
+ const u8 *payload = buf;
+ size_t payload_size = size;
+ const u32 *src;
+
+ if (size < sizeof(__le16))
+ return -EINVAL;

/* Check if the firmware has a 16-byte Freescale header, skip it */
- if (buf[0] == 'M' && buf[1] == 'X')
- src += 4;
+ if (buf[0] == 'M' && buf[1] == 'X') {
+ if (size < 16 + sizeof(__le16))
+ return -EINVAL;
+
+ payload += 16;
+ payload_size -= 16;
+ }
+
+ src = (const u32 *)payload;
/*
* Check whether the firmware is in native order or pre-reordered for
* memory access. The first instruction opcode always is 0xe40e.
*/
- if (__le16_to_cpup((__le16 *)src) == 0xe40e) {
+ if (__le16_to_cpup((__le16 *)payload) == 0xe40e) {
+ size_t words = payload_size / sizeof(u32);
u32 *dst = dev->codebuf.vaddr;
int i;

+ if (payload_size % sizeof(u32))
+ return -EINVAL;
+
/* Firmware in native order, reorder while copying */
if (dev->devtype->product == CODA_DX6) {
- for (i = 0; i < (size - 16) / 4; i++)
+ for (i = 0; i < words; i++)
dst[i] = (src[i] << 16) | (src[i] >> 16);
} else {
- for (i = 0; i < (size - 16) / 4; i += 2) {
+ if (words % 2)
+ return -EINVAL;
+
+ for (i = 0; i < words; i += 2) {
dst[i] = (src[i + 1] << 16) | (src[i + 1] >> 16);
dst[i + 1] = (src[i] << 16) | (src[i] >> 16);
}
}
} else {
/* Copy the already reordered firmware image */
- memcpy(dev->codebuf.vaddr, src, size);
+ memcpy(dev->codebuf.vaddr, payload, payload_size);
}
+
+ return 0;
}

static void coda_fw_callback(const struct firmware *fw, void *context);
@@ -3007,8 +3028,10 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
if (ret < 0)
goto put_pm;

- coda_copy_firmware(dev, fw->data, fw->size);
+ ret = coda_copy_firmware(dev, fw->data, fw->size);
release_firmware(fw);
+ if (ret < 0)
+ goto put_pm;

ret = coda_hw_init(dev);
if (ret < 0) {
--
2.43.0