From f54498b45795194df671207c6ef3d6cd6d0c0ebb Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 31 Oct 2014 16:36:31 +0000 Subject: [PATCH] Avoid allocating over-large buffers when parsing corrupt binaries. PR binutils/17512 * coffgen.c (_bfd_coff_get_external_symbols): Do not try to load a symbol table bigger than the file. * elf.c (bfd_elf_get_str_section): Do not try to load a string table bigger than the file. * readelf.c (process_program_headers): Avoid memory exhaustion due to corrupt values in a dynamis segment header. (get_32bit_elf_symbols): Do not attempt to read an over-large section. (get_64bit_elf_symbols): Likewise. --- bfd/ChangeLog | 8 ++++++++ bfd/coffgen.c | 5 +++++ bfd/elf.c | 5 +++++ binutils/ChangeLog | 9 +++++++++ binutils/readelf.c | 32 ++++++++++++++++++++++++++++---- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c15e8cb703..accbcc953e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2014-10-31 Nick Clifton + + PR binutils/17512 + * coffgen.c (_bfd_coff_get_external_symbols): Do not try to load a + symbol table bigger than the file. + * elf.c (bfd_elf_get_str_section): Do not try to load a string + table bigger than the file. + 2014-10-30 Nick Clifton PR binutils/17512 diff --git a/bfd/coffgen.c b/bfd/coffgen.c index a1a032543e..f18ddab346 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -1616,6 +1616,11 @@ _bfd_coff_get_external_symbols (bfd *abfd) if (size == 0) return TRUE; + /* PR binutils/17512: Do not even try to load + a symbol table bigger than the entire file... */ + if (size >= (bfd_size_type) bfd_get_size (abfd)) + return FALSE; + syms = bfd_malloc (size); if (syms == NULL) return FALSE; diff --git a/bfd/elf.c b/bfd/elf.c index 9c4dcdf452..7cc0ce1fa6 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -294,6 +294,11 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) offset = i_shdrp[shindex]->sh_offset; shstrtabsize = i_shdrp[shindex]->sh_size; + /* PR binutils/17512: Do not even try to load + a string table bigger than the entire file... */ + if (shstrtabsize >= (bfd_size_type) bfd_get_size (abfd)) + return NULL; + /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 diff --git a/binutils/ChangeLog b/binutils/ChangeLog index ec8a9e8be2..993f15caaa 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,12 @@ +2014-10-31 Nick Clifton + + PR binutils/17512 + * readelf.c (process_program_headers): Avoid memory exhaustion due + to corrupt values in a dynamis segment header. + (get_32bit_elf_symbols): Do not attempt to read an over-large + section. + (get_64bit_elf_symbols): Likewise. + 2014-10-31 Nick Clifton * strings.c: Add new command line option --data to only scan the diff --git a/binutils/readelf.c b/binutils/readelf.c index aea02623c2..6ddc078629 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -167,6 +167,7 @@ char * program_name = "readelf"; static long archive_file_offset; static unsigned long archive_file_size; +static bfd_size_type current_file_size; static unsigned long dynamic_addr; static bfd_size_type dynamic_size; static unsigned int dynamic_nent; @@ -4341,6 +4342,9 @@ process_program_headers (FILE * file) } } + if (do_segments) + putc ('\n', stdout); + switch (segment->p_type) { case PT_DYNAMIC: @@ -4351,6 +4355,12 @@ process_program_headers (FILE * file) section in the DYNAMIC segment. */ dynamic_addr = segment->p_offset; dynamic_size = segment->p_filesz; + /* PR binutils/17512: Avoid corrupt dynamic section info in the segment. */ + if (dynamic_addr + dynamic_size >= current_file_size) + { + error (_("the dynamic segment offset + size exceeds the size of the file\n")); + dynamic_addr = dynamic_size = 0; + } /* Try to locate the .dynamic section. If there is a section header table, we can easily locate it. */ @@ -4404,14 +4414,11 @@ process_program_headers (FILE * file) error (_("Unable to read program interpreter name\n")); if (do_segments) - printf (_("\n [Requesting program interpreter: %s]"), + printf (_(" [Requesting program interpreter: %s]\n"), program_interpreter); } break; } - - if (do_segments) - putc ('\n', stdout); } if (do_segments && section_headers != NULL && string_table != NULL) @@ -4580,6 +4587,13 @@ get_32bit_elf_symbols (FILE * file, goto exit_point; } + if (section->sh_size > current_file_size) + { + error (_("Section %s has an invalid sh_size of 0x%lx\n"), + SECTION_NAME (section), section->sh_size); + goto exit_point; + } + number = section->sh_size / section->sh_entsize; if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1) @@ -4660,6 +4674,13 @@ get_64bit_elf_symbols (FILE * file, goto exit_point; } + if (section->sh_size > current_file_size) + { + error (_("Section %s has an invalid sh_size of 0x%lx\n"), + SECTION_NAME (section), section->sh_size); + goto exit_point; + } + number = section->sh_size / section->sh_entsize; if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1) @@ -14886,6 +14907,8 @@ process_file (char * file_name) return 1; } + current_file_size = (bfd_size_type) statbuf.st_size; + if (memcmp (armag, ARMAG, SARMAG) == 0) ret = process_archive (file_name, file, FALSE); else if (memcmp (armag, ARMAGT, SARMAG) == 0) @@ -14903,6 +14926,7 @@ process_file (char * file_name) fclose (file); + current_file_size = 0; return ret; } -- 2.34.1