Skip to content

Commit 9f9967f

Browse files
quic-bjorandeandersson
authored andcommitted
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: 2aad40d ("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>
1 parent 19272b3 commit 9f9967f

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

drivers/soc/qcom/mdt_loader.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,37 @@
1818
#include <linux/slab.h>
1919
#include <linux/soc/qcom/mdt_loader.h>
2020

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+
2152
static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
2253
{
2354
if (phdr->p_type != PT_LOAD)
@@ -82,6 +113,9 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
82113
phys_addr_t max_addr = 0;
83114
int i;
84115

116+
if (!mdt_header_valid(fw))
117+
return -EINVAL;
118+
85119
ehdr = (struct elf32_hdr *)fw->data;
86120
phdrs = (struct elf32_phdr *)(ehdr + 1);
87121

@@ -134,6 +168,9 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
134168
ssize_t ret;
135169
void *data;
136170

171+
if (!mdt_header_valid(fw))
172+
return ERR_PTR(-EINVAL);
173+
137174
ehdr = (struct elf32_hdr *)fw->data;
138175
phdrs = (struct elf32_phdr *)(ehdr + 1);
139176

@@ -214,6 +251,9 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
214251
int ret;
215252
int i;
216253

254+
if (!mdt_header_valid(fw))
255+
return -EINVAL;
256+
217257
ehdr = (struct elf32_hdr *)fw->data;
218258
phdrs = (struct elf32_phdr *)(ehdr + 1);
219259

@@ -310,6 +350,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
310350
if (!fw || !mem_region || !mem_phys || !mem_size)
311351
return -EINVAL;
312352

353+
if (!mdt_header_valid(fw))
354+
return -EINVAL;
355+
313356
is_split = qcom_mdt_bins_are_split(fw, fw_name);
314357
ehdr = (struct elf32_hdr *)fw->data;
315358
phdrs = (struct elf32_phdr *)(ehdr + 1);

0 commit comments

Comments
 (0)