]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
soc: qcom: mdt_loader: Ensure we don't read past the ELF header
authorBjorn Andersson <bjorn.andersson@oss.qualcomm.com>
Fri, 22 Aug 2025 18:49:39 +0000 (14:49 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:21:35 +0000 (16:21 +0200)
[ Upstream commit 9f9967fed9d066ed3dae9372b45ffa4f6fccfeef ]

When the MDT loader is used in remoteproc, the ELF header is sanitized
beforehand, but that's not necessary the case for other clients.

Validate the size of the firmware buffer to ensure that we don't read
past the end as we iterate over the header. e_phentsize and e_shentsize
are validated as well, to ensure that the assumptions about step size in
the traversal are valid.

Fixes: 2aad40d911ee ("remoteproc: Move qcom_mdt_loader into drivers/soc/qcom")
Cc: stable@vger.kernel.org
Reported-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250610-mdt-loader-validation-and-fixes-v2-1-f7073e9ab899@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/soc/qcom/mdt_loader.c

index 6034cd8992b0ea4b5e1206f78a92d8f72bedc042..c2bbde533e66a49183ca9f4c0cb9d688f98fcefb 100644 (file)
 #include <linux/firmware.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/overflow.h>
 #include <linux/qcom_scm.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/soc/qcom/mdt_loader.h>
 
+static bool mdt_header_valid(const struct firmware *fw)
+{
+       const struct elf32_hdr *ehdr;
+       size_t phend;
+       size_t shend;
+
+       if (fw->size < sizeof(*ehdr))
+               return false;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+
+       if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
+               return false;
+
+       if (ehdr->e_phentsize != sizeof(struct elf32_phdr))
+               return false;
+
+       phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff);
+       if (phend > fw->size)
+               return false;
+
+       if (ehdr->e_shentsize != sizeof(struct elf32_shdr))
+               return false;
+
+       shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff);
+       if (shend > fw->size)
+               return false;
+
+       return true;
+}
+
 static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
 {
        if (phdr->p_type != PT_LOAD)
@@ -46,6 +78,9 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
        phys_addr_t max_addr = 0;
        int i;
 
+       if (!mdt_header_valid(fw))
+               return -EINVAL;
+
        ehdr = (struct elf32_hdr *)fw->data;
        phdrs = (struct elf32_phdr *)(ehdr + 1);
 
@@ -92,6 +127,9 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
        size_t ehdr_size;
        void *data;
 
+       if (!mdt_header_valid(fw))
+               return ERR_PTR(-EINVAL);
+
        ehdr = (struct elf32_hdr *)fw->data;
        phdrs = (struct elf32_phdr *)(ehdr + 1);
 
@@ -151,6 +189,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
        if (!fw || !mem_region || !mem_phys || !mem_size)
                return -EINVAL;
 
+       if (!mdt_header_valid(fw))
+               return -EINVAL;
+
        ehdr = (struct elf32_hdr *)fw->data;
        phdrs = (struct elf32_phdr *)(ehdr + 1);