mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-08-02 19:46:09 +08:00
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.
This commit is contained in:
@ -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')
|
||||
|
Reference in New Issue
Block a user