From c8071705c69a13d237aeca4709bf91deaff7e5cb Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 26 Feb 2015 14:21:54 +0000 Subject: Fix undefined arithmetic operations detected by -fsanitize=undefined when running readelf on fuzzed binaries. PR binutils/17512 * dwarf.c (display_debug_loc): Pacify the undefined behaviour sanitizer by simplifying address difference calculation. (struct Frame_Chunk): Change type of cfa_offset to dwarf_vma in order to avoid arithmetic overflows. (frame_display_row): Cast cfa_offset before printing it. (display_debug_frames): Likewise. Check for an unexpected segment size. Chnage type of 'l' local to dwarf_vma and cast it back to an int when printing. (process_cu_tu_index): Tighten check for an invalid ncols value. * readelf.c (process_corefile_note_segment): Check for inote.descdata extending beyond the end of the section. (process_v850_notes): Likewise. --- binutils/ChangeLog | 14 ++++++++++++++ binutils/dwarf.c | 38 +++++++++++++++++++++++--------------- binutils/readelf.c | 24 ++++++++++++++++++------ 3 files changed, 55 insertions(+), 21 deletions(-) (limited to 'binutils') diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 8657b1d..3a42b72 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -4,6 +4,20 @@ * resrc.c (write_rc_messagetable): Tighten check for invalid message lengths. + * dwarf.c (display_debug_loc): Pacify the undefined behaviour + sanitizer by simplifying address difference calculation. + (struct Frame_Chunk): Change type of cfa_offset to dwarf_vma in + order to avoid arithmetic overflows. + (frame_display_row): Cast cfa_offset before printing it. + (display_debug_frames): Likewise. + Check for an unexpected segment size. + Chnage type of 'l' local to dwarf_vma and cast it back to an int + when printing. + (process_cu_tu_index): Tighten check for an invalid ncols value. + * readelf.c (process_corefile_note_segment): Check for + inote.descdata extending beyond the end of the section. + (process_v850_notes): Likewise. + 2015-02-26 Terry Guo * readelf.c (arm_attr_tag_ABI_HardFP_use): Update how we diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 272b41f..5884140 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -4719,11 +4719,11 @@ display_debug_loc (struct dwarf_section *section, void *file) if (start < next) warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"), (unsigned long) (start - section_begin), - (unsigned long) (next - section_begin)); + (unsigned long) offset); else if (start > next) warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"), (unsigned long) (start - section_begin), - (unsigned long) (next - section_begin)); + (unsigned long) offset); } start = next; @@ -5244,7 +5244,7 @@ typedef struct Frame_Chunk dwarf_vma pc_begin; dwarf_vma pc_range; int cfa_reg; - int cfa_offset; + dwarf_vma cfa_offset; unsigned int ra; unsigned char fde_encoding; unsigned char cfa_exp; @@ -5481,7 +5481,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg if (fc->cfa_exp) strcpy (tmp, "exp"); else - sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), fc->cfa_offset); + sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), (int) fc->cfa_offset); printf ("%-8s ", tmp); for (r = 0; r < fc->ncols; r++) @@ -5921,7 +5921,15 @@ display_debug_frames (struct dwarf_section *section, segment_selector = 0; if (fc->segment_size) - SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end); + { + if (fc->segment_size > sizeof (segment_selector)) + { + /* PR 17512: file: 9e196b3e. */ + warn (_("Probably corrupt segment size: %d - using 4 instead\n"), fc->segment_size); + fc->segment_size = 4; + } + SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end); + } fc->pc_begin = get_encoded_value (&start, fc->fde_encoding, section, end); @@ -6123,7 +6131,7 @@ display_debug_frames (struct dwarf_section *section, unsigned char * tmp; unsigned op, opa; unsigned long ul, reg, roffs; - long l; + dwarf_vma l; dwarf_vma ofs; dwarf_vma vma; const char *reg_prefix = ""; @@ -6375,7 +6383,7 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa: %s ofs %d\n", - regname (fc->cfa_reg, 0), fc->cfa_offset); + regname (fc->cfa_reg, 0), (int) fc->cfa_offset); break; case DW_CFA_def_cfa_register: @@ -6389,7 +6397,7 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_offset: fc->cfa_offset = LEB (); if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset); + printf (" DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset); break; case DW_CFA_nop: @@ -6473,7 +6481,7 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n", reg_prefix, regname (reg, 0), - l * fc->data_factor); + (long)(l * fc->data_factor)); if (*reg_prefix == '\0') { fc->col_type[reg] = DW_CFA_offset; @@ -6489,7 +6497,7 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_val_offset_sf: %s%s at cfa%+ld\n", reg_prefix, regname (reg, 0), - l * fc->data_factor); + (long)(l * fc->data_factor)); if (*reg_prefix == '\0') { fc->col_type[reg] = DW_CFA_val_offset; @@ -6504,14 +6512,14 @@ display_debug_frames (struct dwarf_section *section, fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_sf: %s ofs %d\n", - regname (fc->cfa_reg, 0), fc->cfa_offset); + regname (fc->cfa_reg, 0), (int) fc->cfa_offset); break; case DW_CFA_def_cfa_offset_sf: fc->cfa_offset = SLEB (); - fc->cfa_offset = fc->cfa_offset * fc->data_factor; + fc->cfa_offset *= fc->data_factor; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset); + printf (" DW_CFA_def_cfa_offset_sf: %d\n", (int) fc->cfa_offset); break; case DW_CFA_MIPS_advance_loc8: @@ -6546,7 +6554,7 @@ display_debug_frames (struct dwarf_section *section, if (! do_debug_frames_interp || *reg_prefix != '\0') printf (" DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n", reg_prefix, regname (reg, 0), - l * fc->data_factor); + (long)(l * fc->data_factor)); if (*reg_prefix == '\0') { fc->col_type[reg] = DW_CFA_offset; @@ -7026,7 +7034,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display) /* PR 17531: file: 0dd159bf. Check for wraparound with an overlarge ncols value. */ - if ((unsigned int) ((poffsets - ppool) / 4) != ncols) + if (poffsets < ppool || (unsigned int) ((poffsets - ppool) / 4) != ncols) { warn (_("Overlarge number of columns: %x\n"), ncols); return 0; diff --git a/binutils/readelf.c b/binutils/readelf.c index da616b3..06fa8d5 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -15205,6 +15205,7 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) { Elf_External_Note * pnotes; Elf_External_Note * external; + char * end; int res = 1; if (length <= 0) @@ -15221,13 +15222,14 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) (unsigned long) offset, (unsigned long) length); printf (_(" %-20s %10s\tDescription\n"), _("Owner"), _("Data size")); - while ((char *) external < (char *) pnotes + length) + end = (char *) pnotes + length; + while ((char *) external < end) { Elf_Internal_Note inote; size_t min_notesz; char *next; char * temp = NULL; - size_t data_remaining = ((char *) pnotes + length) - (char *) external; + size_t data_remaining = end - (char *) external; if (!is_ia64_vms ()) { @@ -15246,12 +15248,13 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length) inote.descsz = BYTE_GET (external->descsz); inote.descdata = inote.namedata + align_power (inote.namesz, 2); /* PR 17531: file: 3443835e. */ - if (inote.descdata < (char *) pnotes) + if (inote.descdata < (char *) pnotes || inote.descdata > end) { warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz); inote.descdata = inote.namedata; inote.namesz = 0; } + inote.descpos = offset + (inote.descdata - (char *) pnotes); next = inote.descdata + align_power (inote.descsz, 2); } @@ -15358,6 +15361,7 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length) { Elf_External_Note * pnotes; Elf_External_Note * external; + char * end; int res = 1; if (length <= 0) @@ -15369,11 +15373,12 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length) return 0; external = pnotes; + end = (char*) pnotes + length; printf (_("\nDisplaying contents of Renesas V850 notes section at offset 0x%lx with length 0x%lx:\n"), (unsigned long) offset, (unsigned long) length); - while (external < (Elf_External_Note *) ((char *) pnotes + length)) + while ((char *) external + sizeof (Elf_External_Note) < end) { Elf_External_Note * next; Elf_Internal_Note inote; @@ -15385,9 +15390,16 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length) inote.descdata = inote.namedata + align_power (inote.namesz, 2); inote.descpos = offset + (inote.descdata - (char *) pnotes); + if (inote.descdata < (char *) pnotes || inote.descdata >= end) + { + warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz); + inote.descdata = inote.namedata; + inote.namesz = 0; + } + next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2)); - if ( ((char *) next > ((char *) pnotes) + length) + if ( ((char *) next > end) || ((char *) next < (char *) pnotes)) { warn (_("corrupt descsz found in note at offset 0x%lx\n"), @@ -15400,7 +15412,7 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length) external = next; /* Prevent out-of-bounds indexing. */ - if ( inote.namedata + inote.namesz > (char *) pnotes + length + if ( inote.namedata + inote.namesz > end || inote.namedata + inote.namesz < inote.namedata) { warn (_("corrupt namesz found in note at offset 0x%lx\n"), -- cgit v1.1