From d8024a9189b9e686e403512a96e4256823b5c6e4 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 8 Aug 2016 13:20:04 +0100 Subject: Fix seg-faults when running readelf on fuzzed binaries. PR binutils/20440 * dwarf.c (display_debug_lines_decoded): Add checks for running off the end of the section when populating the directory table and file table. (frame_display_row): Set max_regs equal to ncols. (load_specific_debug_section): If the section is compressed, but it is not big enough to hold a compression header then warn and return 0. --- binutils/ChangeLog | 9 +++++++++ binutils/dwarf.c | 31 +++++++++++++++++++++++++++---- binutils/readelf.c | 20 +++++++++++++++++--- 3 files changed, 53 insertions(+), 7 deletions(-) (limited to 'binutils') diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 2ba1bbd..d21c299 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,5 +1,14 @@ 2016-08-08 Nick Clifton + PR binutils/20440 + * dwarf.c (display_debug_lines_decoded): Add checks for running + off the end of the section when populating the directory table and + file table. + (frame_display_row): Set max_regs equal to ncols. + (load_specific_debug_section): If the section is compressed, but + it is not big enough to hold a compression header then warn and + return 0. + PR binutils/20439 * dwarf.c (display_debug_lines_decoded): Check directory and file indicies before using them to access directory and file tables. diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 2f2d8ae..e07f661 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -3252,16 +3252,32 @@ display_debug_lines_decoded (struct dwarf_section *section, /* Traverse the Directory table just to count entries. */ data = standard_opcodes + linfo.li_opcode_base - 1; + /* PR 20440 */ + if (data >= end) + { + warn (_("opcode base of %d extends beyond end of section\n"), + linfo.li_opcode_base); + return 0; + } + if (*data != 0) { unsigned char *ptr_directory_table = data; - while (*data != 0) + while (data < end && *data != 0) { data += strnlen ((char *) data, end - data) + 1; n_directories++; } + /* PR 20440 */ + if (data >= end) + { + warn (_("directory table ends unexpectedly\n")); + n_directories = 0; + break; + } + /* Go through the directory table again to save the directories. */ directory_table = (unsigned char **) xmalloc (n_directories * sizeof (unsigned char *)); @@ -3279,11 +3295,11 @@ display_debug_lines_decoded (struct dwarf_section *section, data++; /* Traverse the File Name table just to count the entries. */ - if (*data != 0) + if (data < end && *data != 0) { unsigned char *ptr_file_name_table = data; - while (*data != 0) + while (data < end && *data != 0) { unsigned int bytes_read; @@ -3300,6 +3316,13 @@ display_debug_lines_decoded (struct dwarf_section *section, n_files++; } + if (data >= end) + { + warn (_("file table ends unexpectedly\n")); + n_files = 0; + break; + } + /* Go through the file table again to save the strings. */ file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry)); @@ -5582,7 +5605,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg unsigned int r; char tmp[100]; - if (*max_regs < fc->ncols) + if (*max_regs != fc->ncols) *max_regs = fc->ncols; if (*need_col_headers) diff --git a/binutils/readelf.c b/binutils/readelf.c index 4c7ad4c..e6674c2 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -5622,6 +5622,7 @@ get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf) if (is_32bit_elf) { Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf; + chdr->ch_type = BYTE_GET (echdr->ch_type); chdr->ch_size = BYTE_GET (echdr->ch_size); chdr->ch_addralign = BYTE_GET (echdr->ch_addralign); @@ -5630,6 +5631,7 @@ get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf) else { Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf; + chdr->ch_type = BYTE_GET (echdr->ch_type); chdr->ch_size = BYTE_GET (echdr->ch_size); chdr->ch_addralign = BYTE_GET (echdr->ch_addralign); @@ -6086,12 +6088,15 @@ process_section_headers (FILE * file) /* Minimum section size is 12 bytes for 32-bit compression header + 12 bytes for compressed data header. */ unsigned char buf[24]; + assert (sizeof (buf) >= sizeof (Elf64_External_Chdr)); if (get_data (&buf, (FILE *) file, section->sh_offset, 1, sizeof (buf), _("compression header"))) { Elf_Internal_Chdr chdr; - get_compression_header (&chdr, buf); + + (void) get_compression_header (&chdr, buf); + if (chdr.ch_type == ELFCOMPRESS_ZLIB) printf (" ZLIB, "); else @@ -12573,8 +12578,17 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, if ((sec->sh_flags & SHF_COMPRESSED) != 0) { Elf_Internal_Chdr chdr; - unsigned int compression_header_size - = get_compression_header (&chdr, start); + unsigned int compression_header_size; + + if (size < sizeof chdr) + { + warn (_("compressed section %s is too small to contain a compression header"), + section->name); + return 0; + } + + compression_header_size = get_compression_header (&chdr, start); + if (chdr.ch_type != ELFCOMPRESS_ZLIB) { warn (_("section '%s' has unsupported compress type: %d\n"), -- cgit v1.1