lib/buildid: take into account e_phoff when fetching program headers
Current code assumption is that program (segment) headers are following ELF header immediately. This is a common case, but is not guaranteed. So take into account e_phoff field of the ELF header when accessing program headers. Reviewed-by: Eduard Zingerman <eddyz87@gmail.com> Reported-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/r/20240829174232.3133883-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
de3ec364c3
commit
d4deb82423
@ -213,28 +213,26 @@ static int get_build_id_32(struct freader *r, unsigned char *build_id, __u32 *si
|
||||
{
|
||||
const Elf32_Ehdr *ehdr;
|
||||
const Elf32_Phdr *phdr;
|
||||
__u32 phnum, i;
|
||||
__u32 phnum, phoff, i;
|
||||
|
||||
ehdr = freader_fetch(r, 0, sizeof(Elf32_Ehdr));
|
||||
if (!ehdr)
|
||||
return r->err;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
* Neither ELF spec nor ELF loader require that program headers
|
||||
* start immediately after ELF header.
|
||||
*/
|
||||
if (ehdr->e_phoff != sizeof(Elf32_Ehdr))
|
||||
return -EINVAL;
|
||||
|
||||
/* subsequent freader_fetch() calls invalidate pointers, so remember locally */
|
||||
phnum = READ_ONCE(ehdr->e_phnum);
|
||||
phoff = READ_ONCE(ehdr->e_phoff);
|
||||
|
||||
/* only supports phdr that fits in one page */
|
||||
if (phnum > (PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
|
||||
return -EINVAL;
|
||||
|
||||
/* check that phoff is not large enough to cause an overflow */
|
||||
if (phoff + phnum * sizeof(Elf32_Phdr) < phoff)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < phnum; ++i) {
|
||||
phdr = freader_fetch(r, i * sizeof(Elf32_Phdr), sizeof(Elf32_Phdr));
|
||||
phdr = freader_fetch(r, phoff + i * sizeof(Elf32_Phdr), sizeof(Elf32_Phdr));
|
||||
if (!phdr)
|
||||
return r->err;
|
||||
|
||||
@ -252,27 +250,26 @@ static int get_build_id_64(struct freader *r, unsigned char *build_id, __u32 *si
|
||||
const Elf64_Ehdr *ehdr;
|
||||
const Elf64_Phdr *phdr;
|
||||
__u32 phnum, i;
|
||||
__u64 phoff;
|
||||
|
||||
ehdr = freader_fetch(r, 0, sizeof(Elf64_Ehdr));
|
||||
if (!ehdr)
|
||||
return r->err;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
* Neither ELF spec nor ELF loader require that program headers
|
||||
* start immediately after ELF header.
|
||||
*/
|
||||
if (ehdr->e_phoff != sizeof(Elf64_Ehdr))
|
||||
return -EINVAL;
|
||||
|
||||
/* subsequent freader_fetch() calls invalidate pointers, so remember locally */
|
||||
phnum = READ_ONCE(ehdr->e_phnum);
|
||||
phoff = READ_ONCE(ehdr->e_phoff);
|
||||
|
||||
/* only supports phdr that fits in one page */
|
||||
if (phnum > (PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
|
||||
return -EINVAL;
|
||||
|
||||
/* check that phoff is not large enough to cause an overflow */
|
||||
if (phoff + phnum * sizeof(Elf64_Phdr) < phoff)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < phnum; ++i) {
|
||||
phdr = freader_fetch(r, i * sizeof(Elf64_Phdr), sizeof(Elf64_Phdr));
|
||||
phdr = freader_fetch(r, phoff + i * sizeof(Elf64_Phdr), sizeof(Elf64_Phdr));
|
||||
if (!phdr)
|
||||
return r->err;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user