diff options
author | Nick Clifton <nickc@redhat.com> | 2014-11-26 14:11:23 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-11-26 14:11:23 +0000 |
commit | a11652892c18324bf3abb8b25c01475e5a18632a (patch) | |
tree | 651732ecd80594056102f5b551cc7ed6f0b5143f /binutils | |
parent | 0cfd832fc7d4f1b5633248754dcc75fa90b5475b (diff) | |
download | gdb-a11652892c18324bf3abb8b25c01475e5a18632a.zip gdb-a11652892c18324bf3abb8b25c01475e5a18632a.tar.gz gdb-a11652892c18324bf3abb8b25c01475e5a18632a.tar.bz2 |
More fixes for memory access errors triggered by attemps to examine corrupted binaries.
PR binutils/17512
* dwarf.c (display_block): Do nothing if the block starts after
the end of the buffer.
(read_and_display_attr_value): Add range checks.
(struct Frame_Chunk): Make the ncols and ra fields unsigned.
(frame_need_space): Test for an ncols of zero.
(read_cie): Fail if the augmentation data extends off the end of
the buffer.
(display_debug_frames): Add checks for read_cie failing. Add
range checks.
* coff-h8300.c (rtype2howto): Replace abort with returning a NULL
value.
* coff-h8500.c (rtype2howto): Likewise.
* coff-tic30.c (rtype2howto): Likewise.
* coff-z80.c (rtype2howto): Likewise.
* coff-z8k.c (rtype2howto): Likewise.
* coff-ia64.c (RTYPE2HOWTO): Always return a valid howto.
* coff-m68k.c (m68k_rtype2howto): Return a NULL howto if none
could be found.
* coff-mcore.c (RTYPE2HOWTO): Add range checking.
* coff-w65.c (rtype2howto): Likewise.
* coff-we32k.c (RTYPE2HOWTO): Likewise.
* pe-mips.c (RTYPE2HOWTO): Likewise.
* coff-x86_64.c (coff_amd64_reloc): Likewise. Replace abort with
an error return.
* coffcode.h (coff_slurp_reloc_table): Allow the rel parameter to
be unused.
* coffgen.c (make_a_section_from_file): Check the length of a
section name before testing to see if it is a debug section name.
(coff_object_p): Zero out any uninitialised bytes in the opt
header.
* ecoff.c (_bfd_ecoff_slurp_symbolic_info): Test for the raw
source being empty when there are values to be processed.
(_bfd_ecoff_slurp_symbol_table): Add range check.
* mach-o.c (bfd_mach_o_canonicalize_one_reloc): Likewise.
(bfd_mach_o_mangle_sections): Move test for too many sections to
before the allocation of the section table.
(bfd_mach_o_read_symtab_strtab): If the read fails, free the
memory and nullify the symbol pointer.
* reloc.c (bfd_generic_get_relocated_section_contents): Add
handling of a bfd_reloc_notsupported return value.
* versados.c (EDATA): Add range checking.
(get_record): Likewise.
(process_otr): Check for contents being available before updating
them.
(versados_canonicalize_reloc): Add range check.
Diffstat (limited to 'binutils')
-rw-r--r-- | binutils/ChangeLog | 13 | ||||
-rw-r--r-- | binutils/dwarf.c | 91 |
2 files changed, 81 insertions, 23 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 86c8555..542d788 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,16 @@ +2014-11-26 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * dwarf.c (display_block): Do nothing if the block starts after + the end of the buffer. + (read_and_display_attr_value): Add range checks. + (struct Frame_Chunk): Make the ncols and ra fields unsigned. + (frame_need_space): Test for an ncols of zero. + (read_cie): Fail if the augmentation data extends off the end of + the buffer. + (display_debug_frames): Add checks for read_cie failing. Add + range checks. + 2014-11-25 H.J. Lu <hongjiu.lu@intel.com> * objdump.c (objdump_print_symname): Replace diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 8213f4d..622fe91 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -861,6 +861,8 @@ display_block (unsigned char *data, dwarf_vma maxlen; printf (_(" %s byte block: "), dwarf_vmatoa ("u", length)); + if (data > end) + return (unsigned char *) end; maxlen = (dwarf_vma) (end - data); length = length > maxlen ? maxlen : length; @@ -1654,6 +1656,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; + if (block_start >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } /* PR 17512: file: 008-103549-0.001:0.1. */ if (block_start + uvalue > end) { @@ -1669,6 +1677,12 @@ 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 >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } if (block_start + uvalue > end) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); @@ -1683,6 +1697,12 @@ 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 >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } if (block_start + uvalue > end) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); @@ -1697,6 +1717,13 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_block4: SAFE_BYTE_GET (uvalue, data, 4, end); block_start = data + 4; + /* PR 17512: file: 3371-3907-0.004. */ + if (block_start >= end) + { + warn (_("Block ends prematurely\n")); + uvalue = 0; + block_start = end; + } if (block_start + uvalue > end) { warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); @@ -5080,7 +5107,7 @@ typedef struct Frame_Chunk { struct Frame_Chunk *next; unsigned char *chunk_start; - int ncols; + unsigned int ncols; /* DW_CFA_{undefined,same_value,offset,register,unreferenced} */ short int *col_type; int *col_offset; @@ -5091,7 +5118,7 @@ typedef struct Frame_Chunk dwarf_vma pc_range; int cfa_reg; int cfa_offset; - int ra; + unsigned int ra; unsigned char fde_encoding; unsigned char cfa_exp; unsigned char ptr_size; @@ -5106,13 +5133,13 @@ static unsigned int dwarf_regnames_count; in the frame info. */ #define DW_CFA_unreferenced (-1) -/* Return 0 if not more space is needed, 1 if more space is needed, +/* Return 0 if no more space is needed, 1 if more space is needed, -1 for invalid reg. */ static int frame_need_space (Frame_Chunk *fc, unsigned int reg) { - int prev = fc->ncols; + unsigned int prev = fc->ncols; if (reg < (unsigned int) fc->ncols) return 0; @@ -5122,6 +5149,11 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg) return -1; fc->ncols = reg + 1; + /* PR 17512: file: 10450-2643-0.004. + If reg == -1 then this can happen... */ + if (fc->ncols == 0) + return -1; + fc->col_type = (short int *) xcrealloc (fc->col_type, fc->ncols, sizeof (short int)); fc->col_offset = (int *) xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); @@ -5280,9 +5312,9 @@ regname (unsigned int regno, int row) } static void -frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) +frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_regs) { - int r; + unsigned int r; char tmp[100]; if (*max_regs < fc->ncols) @@ -5422,6 +5454,12 @@ read_cie (unsigned char *start, unsigned char *end, augmentation_data_len = LEB (); augmentation_data = start; start += augmentation_data_len; + /* PR 17512: file: 11042-2589-0.004. */ + if (start > end) + { + warn (_("Augmentation data too long: 0x%lx"), augmentation_data_len); + return end; + } } if (augmentation_data_len) @@ -5430,7 +5468,7 @@ read_cie (unsigned char *start, unsigned char *end, p = (unsigned char *) fc->augmentation + 1; q = augmentation_data; - while (1) + while (p < end && q < augmentation_data + augmentation_data_len) { if (*p == 'L') q++; @@ -5469,7 +5507,7 @@ display_debug_frames (struct dwarf_section *section, Frame_Chunk *rs; int is_eh = strcmp (section->name, ".eh_frame") == 0; unsigned int length_return; - int max_regs = 0; + unsigned int max_regs = 0; const char *bad_reg = _("bad register: "); int saved_eh_addr_size = eh_addr_size; @@ -5534,18 +5572,19 @@ display_debug_frames (struct dwarf_section *section, || (offset_size == 8 && cie_id == DW64_CIE_ID))) { int version; - int mreg; + unsigned int mreg; start = read_cie (start, end, &cie, &version, &augmentation_data_len, &augmentation_data); /* PR 17512: file: 027-135133-0.005. */ if (cie == NULL) break; + fc = cie; fc->next = chunks; chunks = fc; fc->chunk_start = saved_start; - mreg = max_regs - 1; + mreg = max_regs > 0 ? max_regs - 1 : 0; if (mreg < fc->ra) mreg = fc->ra; frame_need_space (fc, mreg); @@ -5578,8 +5617,11 @@ display_debug_frames (struct dwarf_section *section, if (augmentation_data_len) { unsigned long i; + printf (" Augmentation data: "); for (i = 0; i < augmentation_data_len; ++i) + /* FIXME: If do_wide is FALSE, then we should + add carriage returns at 80 columns... */ printf (" %02x", augmentation_data[i]); putchar ('\n'); } @@ -5635,14 +5677,20 @@ display_debug_frames (struct dwarf_section *section, || (off_size == 8 && c_id == DW64_CIE_ID))) { int version; - int mreg; + unsigned int mreg; read_cie (cie_scan, end, &cie, &version, &augmentation_data_len, &augmentation_data); + /* PR 17512: file: 3450-2098-0.004. */ + if (cie == NULL) + { + warn (_("Failed to read CIE information\n")); + break; + } cie->next = forward_refs; forward_refs = cie; cie->chunk_start = look_for; - mreg = max_regs - 1; + mreg = max_regs > 0 ? max_regs - 1 : 0; if (mreg < cie->ra) mreg = cie->ra; frame_need_space (cie, mreg); @@ -5665,7 +5713,7 @@ display_debug_frames (struct dwarf_section *section, fc->ncols = 0; fc->col_type = (short int *) xmalloc (sizeof (short int)); fc->col_offset = (int *) xmalloc (sizeof (int)); - frame_need_space (fc, max_regs - 1); + frame_need_space (fc, max_regs > 0 ? max_regs - 1 : 0); cie = fc; fc->augmentation = ""; fc->fde_encoding = 0; @@ -5688,7 +5736,7 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_reg = cie->cfa_reg; fc->cfa_offset = cie->cfa_offset; fc->ra = cie->ra; - frame_need_space (fc, max_regs - 1); + frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0); fc->fde_encoding = cie->fde_encoding; } @@ -6167,10 +6215,9 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_expression: ul = LEB (); - if (start >= block_end) + if (start >= block_end || start + ul > block_end) { - printf (" DW_CFA_def_cfa_expression: <corrupt>\n"); - warn (_("Corrupt length field in DW_CFA_def_cfa_expression\n")); + printf (_(" DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul); break; } if (! do_debug_frames_interp) @@ -6190,10 +6237,9 @@ display_debug_frames (struct dwarf_section *section, if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; /* PR 17512: file: 069-133014-0.006. */ - if (start >= block_end) + if (start >= block_end || start + ul > block_end) { - printf (" DW_CFA_expression: <corrupt>\n"); - warn (_("Corrupt length field in DW_CFA_expression\n")); + printf (_(" DW_CFA_expression: <corrupt len %lu>\n"), ul); break; } if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -6214,10 +6260,9 @@ display_debug_frames (struct dwarf_section *section, ul = LEB (); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; - if (start >= block_end) + if (start >= block_end || start + ul > block_end) { - printf (" DW_CFA_val_expression: <corrupt>\n"); - warn (_("Corrupt length field in DW_CFA_val_expression\n")); + printf (" DW_CFA_val_expression: <corrupt len %lu>\n", ul); break; } if (! do_debug_frames_interp || *reg_prefix != '\0') |