diff options
author | Nick Clifton <nickc@redhat.com> | 2014-11-12 22:39:58 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-11-12 22:39:58 +0000 |
commit | f41e4712a7b7ac60f181e7dfc984ca35c222f0d7 (patch) | |
tree | 6ac324979fd61983fb6a27dccf9fe306725789fa /binutils/dwarf.c | |
parent | 40e91bc71f7993f2064cec4ffd007f2c814a1b29 (diff) | |
download | binutils-gdb-f41e4712a7b7ac60f181e7dfc984ca35c222f0d7.tar.gz |
Fix more memory faults uncovered by fuzzing various executables.
PR binutils/17512
* dwarf.c (read_and_display_attr_value): Check that we do not read
past end.
(display_debug_pubnames_worker): Add range checks.
(process_debug_info): Check for invalid pointer sizes.
(display_loc_list): Likewise.
(display_loc_list_dwo): Likewise.
(display_debug_ranges): Likewise.
(display_debug_aranges): Check for invalid address size.
(read_cie): Add range checks. Replace call strchr with while loop.
* objdump.c (dump_dwarf): Replace abort with a warning message.
(print_section_stabs): Improve range checks.
* rdcoff.c (coff_get_slot): Use long for indx parameter type.
Add check for an excesively large index.
* rddbg.c (read_section_stabs_debugging_info): Zero terminate the
string table. Avoid walking off the end of the stabs data.
* stabs.c (parse_stab_string): Add check for a NULL name.
PR binutils/17512
* coffcode.h (coff_slurp_line_table): Set the line number of
corrupt entries to -1.
(coff_slurp_symbol_table): Alway initialise the value of the
symbol.
* coffgen.c (coff_print_symbol): Check that the combined pointer
is valid.
(coff_print_symbol): Do not print negative line numbers.
* peXXigen.c (pe_print_idata): Add range checking displaying
member names.
Diffstat (limited to 'binutils/dwarf.c')
-rw-r--r-- | binutils/dwarf.c | 144 |
1 files changed, 108 insertions, 36 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c index ee982debe9f..38ea2560f86 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -399,7 +399,7 @@ process_extended_line_op (unsigned char * data, if (len == 0 || data == end) { - warn (_("badly formed extended line op encountered!\n")); + warn (_("Badly formed extended line op encountered!\n")); return bytes_read; } @@ -1464,9 +1464,9 @@ read_and_display_attr_value (unsigned long attribute, unsigned char * orig_data = data; unsigned int bytes_read; - if (data == end && form != DW_FORM_flag_present) + if (data > end || (data == end && form != DW_FORM_flag_present)) { - warn (_("corrupt attribute\n")); + warn (_("Corrupt attribute\n")); return data; } @@ -1623,6 +1623,12 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_exprloc: uvalue = read_uleb128 (data, & bytes_read, end); block_start = data + bytes_read; + /* PR 17512: file: 008-103549-0.001:0.1. */ + if (block_start + uvalue > end) + { + warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); + uvalue = end - block_start; + } if (do_loc) data = block_start + uvalue; else @@ -1632,6 +1638,11 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block1: SAFE_BYTE_GET (uvalue, data, 1, end); block_start = data + 1; + if (block_start + uvalue > end) + { + warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); + uvalue = end - block_start; + } if (do_loc) data = block_start + uvalue; else @@ -1641,6 +1652,11 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block2: SAFE_BYTE_GET (uvalue, data, 2, end); block_start = data + 2; + if (block_start + uvalue > end) + { + warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); + uvalue = end - block_start; + } if (do_loc) data = block_start + uvalue; else @@ -1650,6 +1666,11 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block4: SAFE_BYTE_GET (uvalue, data, 4, end); block_start = data + 4; + if (block_start + uvalue > end) + { + warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); + uvalue = end - block_start; + } if (do_loc) data = block_start + uvalue; else @@ -2184,7 +2205,7 @@ process_debug_info (struct dwarf_section *section, if (num_units == 0) { - error (_("No comp units in %s section ?"), section->name); + error (_("No comp units in %s section ?\n"), section->name); return 0; } @@ -2193,7 +2214,7 @@ process_debug_info (struct dwarf_section *section, sizeof (* debug_information)); if (debug_information == NULL) { - error (_("Not enough memory for a debug info array of %u entries"), + error (_("Not enough memory for a debug info array of %u entries\n"), num_units); return 0; } @@ -2271,6 +2292,13 @@ process_debug_info (struct dwarf_section *section, } SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end); + /* PR 17512: file: 001-108546-0.001:0.1. */ + if (compunit.cu_pointer_size < 2 || compunit.cu_pointer_size > 8) + { + warn (_("Invalid pointer size (%d) in compunit header, using %d instead\n"), + compunit.cu_pointer_size, offset_size); + compunit.cu_pointer_size = offset_size; + } if (do_types) { @@ -2602,20 +2630,20 @@ read_debug_line_header (struct dwarf_section * section, SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end); if (linfo->li_length == 0xffffffff) - { - /* This section is 64-bit DWARF 3. */ + { + /* This section is 64-bit DWARF 3. */ SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 8, end); - offset_size = 8; - initial_length_size = 12; - } - else - { - offset_size = 4; - initial_length_size = 4; - } + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } if (linfo->li_length + initial_length_size > section->size) - { + { /* If the length is just a bias against the initial_length_size then this means that the field has a relocation against it which has not been applied. (Ie we are dealing with an object file, not a linked @@ -2627,11 +2655,10 @@ read_debug_line_header (struct dwarf_section * section, } else { - warn (_("The line info appears to be corrupt - " - "the section is too small\n")); + warn (_("The line info appears to be corrupt - the section is too small\n")); return NULL; } - } + } /* Get and check the version number. */ SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end); @@ -2639,25 +2666,25 @@ read_debug_line_header (struct dwarf_section * section, if (linfo->li_version != 2 && linfo->li_version != 3 && linfo->li_version != 4) - { - warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n")); + { + warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n")); return NULL; - } + } SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end); SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end); if (linfo->li_version >= 4) - { + { SAFE_BYTE_GET_AND_INC (linfo->li_max_ops_per_insn, hdrptr, 1, end); if (linfo->li_max_ops_per_insn == 0) - { - warn (_("Invalid maximum operations per insn.\n")); + { + warn (_("Invalid maximum operations per insn.\n")); return NULL; - } } - else + } + else linfo->li_max_ops_per_insn = 1; SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end); @@ -3204,7 +3231,7 @@ display_debug_lines_decoded (struct dwarf_section *section, if (ext_op_code_len == 0) { - warn (_("badly formed extended line op encountered!\n")); + warn (_("Badly formed extended line op encountered!\n")); break; } ext_op_code_len += bytes_read; @@ -3598,11 +3625,17 @@ display_debug_pubnames_worker (struct dwarf_section *section, do { + bfd_size_type maxprint; + SAFE_BYTE_GET (offset, data, offset_size, end); if (offset != 0) { data += offset_size; + if (data >= end) + break; + maxprint = (end - data) - 1; + if (is_gnu) { unsigned int kind_data; @@ -3612,6 +3645,7 @@ display_debug_pubnames_worker (struct dwarf_section *section, SAFE_BYTE_GET (kind_data, data, 1, end); data++; + maxprint --; /* GCC computes the kind as the upper byte in the CU index word, and then right shifts it by the CU index size. Left shift KIND to where the gdb-index.h accessor macros @@ -3620,13 +3654,16 @@ display_debug_pubnames_worker (struct dwarf_section *section, kind = GDB_INDEX_SYMBOL_KIND_VALUE (kind_data); kind_name = get_gdb_index_symbol_kind_name (kind); is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (kind_data); - printf (" %-6lx %s,%-10s %s\n", + printf (" %-6lx %s,%-10s %.*s\n", offset, is_static ? _("s") : _("g"), - kind_name, data); + kind_name, (int) maxprint, data); } else - printf (" %-6lx\t%s\n", offset, data); - data += strnlen ((char *) data, end - data) + 1; + printf (" %-6lx\t%.*s\n", offset, (int) maxprint, data); + + data += strnlen ((char *) data, maxprint) + 1; + if (data >= end) + break; } } while (offset != 0); @@ -4135,6 +4172,13 @@ display_loc_list (struct dwarf_section *section, unsigned short length; int need_frame_base; + if (pointer_size < 2 || pointer_size > 8) + { + warn (_("Invalid pointer size (%d) in debug info for entry %d\n"), + pointer_size, debug_info_entry); + return; + } + while (1) { if (start + 2 * pointer_size > section_end) @@ -4247,6 +4291,13 @@ display_loc_list_dwo (struct dwarf_section *section, unsigned int idx; unsigned int bytes_read; + if (pointer_size < 2 || pointer_size > 8) + { + warn (_("Invalid pointer size (%d) in debug info for entry %d\n"), + pointer_size, debug_info_entry); + return; + } + while (1) { printf (" %8.8lx ", offset + (start - *start_ptr)); @@ -4647,7 +4698,8 @@ display_debug_aranges (struct dwarf_section *section, address_size = arange.ar_pointer_size + arange.ar_segment_size; - if (address_size == 0) + /* PR 17512: file: 001-108546-0.001:0.1. */ + if (address_size == 0 || address_size > 8) { error (_("Invalid address size in %s section!\n"), section->name); @@ -4886,11 +4938,18 @@ display_debug_ranges (struct dwarf_section *section, unsigned long base_address; pointer_size = debug_info_p->pointer_size; - offset = range_entry->ranges_offset; next = section_begin + offset; base_address = debug_info_p->base_address; + /* PR 17512: file: 001-101485-0.001:0.1. */ + if (pointer_size < 2 || pointer_size > 8) + { + warn (_("Corrupt pointer size (%d) in debug entry at offset %8.8lx\n"), + pointer_size, offset); + continue; + } + if (dwarf_check != 0 && i > 0) { if (start < next) @@ -5243,6 +5302,10 @@ read_cie (unsigned char *start, unsigned char *end, unsigned char *augmentation_data = NULL; unsigned long augmentation_data_len = 0; + /* PR 17512: file: 001-228113-0.004. */ + if (start >= end) + return end; + fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); memset (fc, 0, sizeof (Frame_Chunk)); @@ -5252,7 +5315,16 @@ read_cie (unsigned char *start, unsigned char *end, version = *start++; fc->augmentation = (char *) start; - start = (unsigned char *) strchr ((char *) start, '\0') + 1; + /* PR 17512: file: 001-228113-0.004. + Skip past augmentation name, but avoid running off the end of the data. */ + while (start < end) + if (* start ++ == '\0') + break; + if (start == end) + { + warn (_("No terminator for augmentation name\n")); + return start; + } if (strcmp (fc->augmentation, "eh") == 0) start += eh_addr_size; @@ -6140,7 +6212,7 @@ display_debug_frames (struct dwarf_section *section, if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user) printf (_(" DW_CFA_??? (User defined call frame op: %#x)\n"), op); else - warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op); + warn (_("Unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op); start = block_end; } } |