prestera_ldr_fw_send() passes complete 1024-byte blocks to the loader and then sends fw_size - pos as the final chunk. Firmware header validation does not require the payload size to be a multiple of four. Consequently that last chunk can end with one to three bytes, while prestera_ldr_send() still loads a full u32 from it and transfers bytes beyond the supplied firmware image to the device. Reserve space for the rounded-up transfer, use unaligned-safe full-word loads, and construct the final word from only the remaining bytes with zero padding. The firmware image-size register still describes the exact payload size. Preserve the existing native-word load and writel_relaxed() byte-order convention. The issue was found by our static-analysis tool and manually reviewed. Fixes: 4c2703dfd7fa ("net: marvell: prestera: Add PCI interface support") Assisted-by: gpt 5 Signed-off-by: Pengpeng Hou --- Changes since v1: - explain why a short final chunk reaches the loader, as Andrew requested - include linux/unaligned.h to fix the reported undeclared get_unaligned() - use a const full-word source pointer and sizeof(u32) for index movement - rebase on current mainline Previous version: https://lore.kernel.org/all/20260830142404.37663-1-pengpeng@iscas.ac.cn/ .../net/ethernet/marvell/prestera/prestera_pci.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c index 1ad0e62a8433ba91a9c019aa7f277c6c9f65f58e..4492c35ea5d388ef485f424d88fc1f9b0f7ad29e 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -589,18 +590,27 @@ static u8 __iomem *prestera_ldr_wr_ptr(struct prestera_fw *fw) static int prestera_ldr_send(struct prestera_fw *fw, const u8 *buf, size_t len) { + size_t write_len = ALIGN(len, sizeof(u32)); + size_t i; int err; - int i; - err = prestera_ldr_wait_buf(fw, len); + err = prestera_ldr_wait_buf(fw, write_len); if (err) { dev_err(fw->dev.dev, "failed wait for sending firmware\n"); return err; } - for (i = 0; i < len; i += 4) { - writel_relaxed(*(u32 *)(buf + i), prestera_ldr_wr_ptr(fw)); - prestera_ldr_wr_idx_move(fw, 4); + for (i = 0; i + sizeof(u32) <= len; i += sizeof(u32)) { + writel_relaxed(get_unaligned((const u32 *)(buf + i)), + prestera_ldr_wr_ptr(fw)); + prestera_ldr_wr_idx_move(fw, sizeof(u32)); + } + if (i < len) { + u32 last = 0; + + memcpy(&last, buf + i, len - i); + writel_relaxed(last, prestera_ldr_wr_ptr(fw)); + prestera_ldr_wr_idx_move(fw, sizeof(u32)); } prestera_ldr_wr_idx_commit(fw); base-commit: 4056b3c9d3c92ea45955641dbafeb9b960e146ef