If there is no e_phoff e_phnum cannot be trusted. Extended phnum can only be gotten if we have an actual section table and a shdr for section zero, Extended phnum can be too large to fit in the file (or a size_t).
Signed-off-by: Mark Wielaard <[email protected]> --- libelf/ChangeLog | 7 +++++++ libelf/elf32_getphdr.c | 6 ++++-- libelf/elf_getphdrnum.c | 18 +++++++++++++----- src/ChangeLog | 6 ++++++ src/readelf.c | 7 ++++++- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/libelf/ChangeLog b/libelf/ChangeLog index beb431f..ef5da43 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,5 +1,12 @@ 2014-11-16 Mark Wielaard <[email protected]> + * elf32_getphdr.c (getphdr_wrlock): Check e_phoff isn't zero. + Check for too many pheaders. + * elf_getphdrnum.c (__elf_getphdrnum_rdlock): Check section zero + actually exists before handling PN_XNUM. + +2014-11-16 Mark Wielaard <[email protected]> + * gelf_getnote.c (gelf_getnote): Check padding overflow. 2014-11-16 Mark Wielaard <[email protected]> diff --git a/libelf/elf32_getphdr.c b/libelf/elf32_getphdr.c index e74e63f..1b82a48 100644 --- a/libelf/elf32_getphdr.c +++ b/libelf/elf32_getphdr.c @@ -76,15 +76,17 @@ __elfw2(LIBELFBITS,getphdr_wrlock) (elf) size_t phnum; if (__elf_getphdrnum_rdlock (elf, &phnum) != 0) goto out; - if (phnum == 0) + if (phnum == 0 || ehdr->e_phoff == 0) { __libelf_seterrno (ELF_E_NO_PHDR); goto out; } + /* Check this doesn't overflow. */ size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr)); - if (ehdr->e_phoff > elf->maximum_size + if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr)) + || ehdr->e_phoff > elf->maximum_size || elf->maximum_size - ehdr->e_phoff < size) { __libelf_seterrno (ELF_E_INVALID_DATA); diff --git a/libelf/elf_getphdrnum.c b/libelf/elf_getphdrnum.c index 99649be..d8e34d7 100644 --- a/libelf/elf_getphdrnum.c +++ b/libelf/elf_getphdrnum.c @@ -1,5 +1,5 @@ /* Return number of program headers in the ELF file. - Copyright (C) 2010 Red Hat, Inc. + Copyright (C) 2010, 2014 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -62,10 +62,18 @@ __elf_getphdrnum_rdlock (elf, dst) /* If there are no section headers, perhaps this is really just 65536 written without PN_XNUM support. Either that or it's bad data. */ - if (likely (scns->cnt > 0)) - *dst = (elf->class == ELFCLASS32 - ? scns->data[0].shdr.e32->sh_info - : scns->data[0].shdr.e64->sh_info); + if (elf->class == ELFCLASS32) + { + if (likely (scns->cnt > 0 + && elf->state.elf32.scns.data[0].shdr.e32 != NULL)) + *dst = scns->data[0].shdr.e32->sh_info; + } + else + { + if (likely (scns->cnt > 0 + && elf->state.elf64.scns.data[0].shdr.e64 != NULL)) + *dst = scns->data[0].shdr.e64->sh_info; + } } return 0; diff --git a/src/ChangeLog b/src/ChangeLog index fefd6c1..737c674 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,11 @@ 2014-11-16 Mark Wielaard <[email protected]> + * readelf (process_elf_file): Set phnum to zero if there aren't + actually any pheaders. + (print_phdr): Check there actually is a phdr. + +2014-11-16 Mark Wielaard <[email protected]> + * readelf.c (print_cfa_program): Check block len before calling print_ops. diff --git a/src/readelf.c b/src/readelf.c index 697a0e5..583b5da 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -835,6 +835,11 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) gettext ("cannot determine number of program headers: %s"), elf_errmsg (-1)); + /* If there isn't actually a program header then set phnum to zero. + Don't do any extra work. gelf_getphdr will always return NULL. */ + if (ehdr->e_phoff == 0) + phnum = 0; + /* For an ET_REL file, libdwfl has adjusted the in-core shdrs and may have applied relocation to some sections. So we need to get a fresh Elf handle on the file to display those. */ @@ -1157,7 +1162,7 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\ static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr) { - if (ehdr->e_phnum == 0) + if (ehdr->e_phnum == 0 || ehdr->e_phoff == 0) /* No program header, this is OK in relocatable objects. */ return; -- 1.8.3.1
