From 957072c18a906a43f0b428997d0c2b0da478213b Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 14 Apr 2010 11:24:15 -0700 Subject: [PATCH] Handle truncated phdrs without crash. --- libelf/ChangeLog | 5 +++++ libelf/elf32_getphdr.c | 7 +++++++ libelf/elf_begin.c | 16 ++++++---------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 2ed2761b7..7e6b99297 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,8 @@ +2010-04-14 Roland McGrath + + * elf32_getphdr.c: Check for e_phoff/size outside the file bounds. + * elf_begin.c (file_read_elf): Don't set .phdr here. + 2010-04-13 Roland McGrath * elf.h: Update from glibc. diff --git a/libelf/elf32_getphdr.c b/libelf/elf32_getphdr.c index 0a617a67e..507fc2aa5 100644 --- a/libelf/elf32_getphdr.c +++ b/libelf/elf32_getphdr.c @@ -105,6 +105,13 @@ __elfw2(LIBELFBITS,getphdr_wrlock) (elf) size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr)); + if (ehdr->e_phoff < elf->maximum_size + || elf->maximum_size - ehdr->e_phoff < size) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + if (elf->map_address != NULL) { /* All the data is already mapped. Use it. */ diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index 0b9583b26..e46add330 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -326,11 +326,9 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, elf->state.elf32.ehdr = ehdr; elf->state.elf32.shdr = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff); - if (ehdr->e_phnum > 0) - /* Assign a value only if there really is a program - header. Otherwise the value remains NULL. */ - elf->state.elf32.phdr - = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff); + + /* Don't precache the phdr pointer here. + elf32_getphdr will validate it against the size when asked. */ for (size_t cnt = 0; cnt < scncnt; ++cnt) { @@ -414,11 +412,9 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, elf->state.elf64.ehdr = ehdr; elf->state.elf64.shdr = (Elf64_Shdr *) ((char *) ehdr + ehdr->e_shoff); - if (ehdr->e_phnum > 0) - /* Assign a value only if there really is a program - header. Otherwise the value remains NULL. */ - elf->state.elf64.phdr - = (Elf64_Phdr *) ((char *) ehdr + ehdr->e_phoff); + + /* Don't precache the phdr pointer here. + elf64_getphdr will validate it against the size when asked. */ for (size_t cnt = 0; cnt < scncnt; ++cnt) { -- 2.47.2