From: Jan Beulich Date: Wed, 7 Dec 2016 12:53:50 +0000 (+0100) Subject: libelf: treat phdr and shdr similarly X-Git-Tag: archive/raspbian/4.11.1-1+rpi1~1^2~66^2~3255 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a01b6d464f05dadf28bfd38612283bd1848f1350;p=xen.git libelf: treat phdr and shdr similarly Just like elf_shdr_count(), elf_phdr_count() better bounds checks the value. Add table entry size checks to elf_init(). Also both program and section headers are optional, and hence their checking better is done conditionally only when any such headers are present. Signed-off-by: Jan Beulich Reviewed-by: Konrad Rzeszutek Wilk Reviewed-by: Roger Pau Monné --- diff --git a/xen/common/libelf/libelf-loader.c b/xen/common/libelf/libelf-loader.c index a72cd8a274..544cfc5b55 100644 --- a/xen/common/libelf/libelf-loader.c +++ b/xen/common/libelf/libelf-loader.c @@ -52,24 +52,45 @@ elf_errorstatus elf_init(struct elf_binary *elf, const char *image_input, size_t elf->class = elf_uval_3264(elf, elf->ehdr, e32.e_ident[EI_CLASS]); elf->data = elf_uval_3264(elf, elf->ehdr, e32.e_ident[EI_DATA]); - /* Sanity check phdr. */ - offset = elf_uval(elf, elf->ehdr, e_phoff) + - elf_uval(elf, elf->ehdr, e_phentsize) * elf_phdr_count(elf); - if ( offset > elf->size ) + /* Sanity check phdr if present. */ + count = elf_phdr_count(elf); + if ( count ) { - elf_err(elf, "ELF: phdr overflow (off %" PRIx64 " > size %lx)\n", - offset, (unsigned long)elf->size); - return -1; + if ( elf_uval(elf, elf->ehdr, e_phentsize) < + elf_size(elf, ELF_HANDLE_DECL(elf_phdr)) ) + { + elf_err(elf, "ELF: phdr too small (%" PRIu64 ")\n", + elf_uval(elf, elf->ehdr, e_phentsize)); + return -1; + } + offset = elf_uval(elf, elf->ehdr, e_phoff) + + elf_uval(elf, elf->ehdr, e_phentsize) * count; + if ( offset > elf->size ) + { + elf_err(elf, "ELF: phdr overflow (off %" PRIx64 " > size %lx)\n", + offset, (unsigned long)elf->size); + return -1; + } } - /* Sanity check shdr. */ - offset = elf_uval(elf, elf->ehdr, e_shoff) + - elf_uval(elf, elf->ehdr, e_shentsize) * elf_shdr_count(elf); - if ( offset > elf->size ) + /* Sanity check shdr if present. */ + count = elf_shdr_count(elf); + if ( count ) { - elf_err(elf, "ELF: shdr overflow (off %" PRIx64 " > size %lx)\n", - offset, (unsigned long)elf->size); - return -1; + if ( elf_uval(elf, elf->ehdr, e_shentsize) < elf_size(elf, shdr) ) + { + elf_err(elf, "ELF: shdr too small (%" PRIu64 ")\n", + elf_uval(elf, elf->ehdr, e_shentsize)); + return -1; + } + offset = elf_uval(elf, elf->ehdr, e_shoff) + + elf_uval(elf, elf->ehdr, e_shentsize) * count; + if ( offset > elf->size ) + { + elf_err(elf, "ELF: shdr overflow (off %" PRIx64 " > size %lx)\n", + offset, (unsigned long)elf->size); + return -1; + } } /* Find section string table. */ @@ -79,7 +100,6 @@ elf_errorstatus elf_init(struct elf_binary *elf, const char *image_input, size_t elf->sec_strtab = elf_section_start(elf, shdr); /* Find symbol table and symbol string table. */ - count = elf_shdr_count(elf); for ( i = 1; i < count; i++ ) { shdr = elf_shdr_by_index(elf, i); diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c index a9edb6a8dc..bf661e7090 100644 --- a/xen/common/libelf/libelf-tools.c +++ b/xen/common/libelf/libelf-tools.c @@ -130,8 +130,11 @@ uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr) unsigned elf_shdr_count(struct elf_binary *elf) { unsigned count = elf_uval(elf, elf->ehdr, e_shnum); - uint64_t max = elf->size / sizeof(Elf32_Shdr); + uint64_t max; + if ( !count ) + return 0; + max = elf->size / elf_uval(elf, elf->ehdr, e_shentsize); if ( max > UINT_MAX ) max = UINT_MAX; if ( count > max ) @@ -144,7 +147,20 @@ unsigned elf_shdr_count(struct elf_binary *elf) unsigned elf_phdr_count(struct elf_binary *elf) { - return elf_uval(elf, elf->ehdr, e_phnum); + unsigned count = elf_uval(elf, elf->ehdr, e_phnum); + uint64_t max; + + if ( !count ) + return 0; + max = elf->size / elf_uval(elf, elf->ehdr, e_phentsize); + if ( max > UINT_MAX ) + max = UINT_MAX; + if ( count > max ) + { + elf_mark_broken(elf, "far too many program headers"); + count = max; + } + return count; } ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *name)