Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

soc: qcom: mdt_loader: Ensure we don't read past the ELF header

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>

authored by

Bjorn Andersson and committed by
Bjorn Andersson
9f9967fe 19272b37

+43
+43
drivers/soc/qcom/mdt_loader.c
··· 18 18 #include <linux/slab.h> 19 19 #include <linux/soc/qcom/mdt_loader.h> 20 20 21 + static bool mdt_header_valid(const struct firmware *fw) 22 + { 23 + const struct elf32_hdr *ehdr; 24 + size_t phend; 25 + size_t shend; 26 + 27 + if (fw->size < sizeof(*ehdr)) 28 + return false; 29 + 30 + ehdr = (struct elf32_hdr *)fw->data; 31 + 32 + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) 33 + return false; 34 + 35 + if (ehdr->e_phentsize != sizeof(struct elf32_phdr)) 36 + return -EINVAL; 37 + 38 + phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff); 39 + if (phend > fw->size) 40 + return false; 41 + 42 + if (ehdr->e_shentsize != sizeof(struct elf32_shdr)) 43 + return -EINVAL; 44 + 45 + shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff); 46 + if (shend > fw->size) 47 + return false; 48 + 49 + return true; 50 + } 51 + 21 52 static bool mdt_phdr_valid(const struct elf32_phdr *phdr) 22 53 { 23 54 if (phdr->p_type != PT_LOAD) ··· 113 82 phys_addr_t max_addr = 0; 114 83 int i; 115 84 85 + if (!mdt_header_valid(fw)) 86 + return -EINVAL; 87 + 116 88 ehdr = (struct elf32_hdr *)fw->data; 117 89 phdrs = (struct elf32_phdr *)(ehdr + 1); 118 90 ··· 167 133 unsigned int i; 168 134 ssize_t ret; 169 135 void *data; 136 + 137 + if (!mdt_header_valid(fw)) 138 + return ERR_PTR(-EINVAL); 170 139 171 140 ehdr = (struct elf32_hdr *)fw->data; 172 141 phdrs = (struct elf32_phdr *)(ehdr + 1); ··· 250 213 void *metadata; 251 214 int ret; 252 215 int i; 216 + 217 + if (!mdt_header_valid(fw)) 218 + return -EINVAL; 253 219 254 220 ehdr = (struct elf32_hdr *)fw->data; 255 221 phdrs = (struct elf32_phdr *)(ehdr + 1); ··· 348 308 int i; 349 309 350 310 if (!fw || !mem_region || !mem_phys || !mem_size) 311 + return -EINVAL; 312 + 313 + if (!mdt_header_valid(fw)) 351 314 return -EINVAL; 352 315 353 316 is_split = qcom_mdt_bins_are_split(fw, fw_name);