diff options
author | Nick Clifton <nickc@redhat.com> | 2017-06-21 18:05:44 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2017-06-21 18:05:44 +0100 |
commit | 7f2c8a1d37af46c46828909b7b748c79aa4b7ff0 (patch) | |
tree | 09ade7d4590196f880186beeac8310999778cb8e /binutils | |
parent | 2c6b98ea6fcc1358639253d4e96c9b55a672fb0c (diff) | |
download | fsf-binutils-gdb-7f2c8a1d37af46c46828909b7b748c79aa4b7ff0.zip fsf-binutils-gdb-7f2c8a1d37af46c46828909b7b748c79aa4b7ff0.tar.gz fsf-binutils-gdb-7f2c8a1d37af46c46828909b7b748c79aa4b7ff0.tar.bz2 |
Fix address violation when reading corrupt DWARF data.
PR binutils/21648
* dwarf.c (LEB): Rename to SKIP_ULEB and READ_ULEB. Add check for
reading a value that is too big for the containing variable.
(SLEB): Rename to SKIP_SLEB and READ_SLEB. Add similar check.
Replace uses of LEB and SLEB with appropriate new macro.
(display_debug_frames): Use an unsigned int for the 'reg'
variable. Use a signed long for the 'l' variable.
Diffstat (limited to 'binutils')
-rw-r--r-- | binutils/ChangeLog | 10 | ||||
-rw-r--r-- | binutils/dwarf.c | 154 |
2 files changed, 106 insertions, 58 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 6997db9..f5da75d 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,13 @@ +2017-06-21 Nick Clifton <nickc@redhat.com> + + PR binutils/21648 + * dwarf.c (LEB): Rename to SKIP_ULEB and READ_ULEB. Add check for + reading a value that is too big for the containing variable. + (SLEB): Rename to SKIP_SLEB and READ_SLEB. Add similar check. + Replace uses of LEB and SLEB with appropriate new macro. + (display_debug_frames): Use an unsigned int for the 'reg' + variable. Use a signed long for the 'l' variable. + 2017-06-19 Nick Clifton <nickc@redhat.com> PR binutils/21619 diff --git a/binutils/dwarf.c b/binutils/dwarf.c index cdedbb2..ee46439 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -313,6 +313,35 @@ read_uleb128 (unsigned char * data, return read_leb128 (data, length_return, FALSE, end); } +#define SKIP_ULEB() read_uleb128 (start, & length_return, end); start += length_return +#define SKIP_SLEB() read_sleb128 (start, & length_return, end); start += length_return + +#define READ_ULEB(var) \ + do \ + { \ + dwarf_vma _val; \ + \ + (var) = _val = read_uleb128 (start, &length_return, end); \ + if ((var) != _val) \ + error (_("Internal error: %s%d: LEB value (%#lx) too large for containing variable\n"), \ + __FILE__, __LINE__, _val); \ + start += length_return; \ + } \ + while (0) + +#define READ_SLEB(var) \ + do \ + { \ + dwarf_signed_vma _val; \ + \ + (var) = _val = read_sleb128 (start, &length_return, end); \ + if ((var) != _val) \ + error (_("Internal error: %s%d: LEB value (%#lx) too large for containing variable\n"), \ + __FILE__, __LINE__, _val); \ + start += length_return; \ + } \ + while (0) + #define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \ do \ { \ @@ -6421,6 +6450,7 @@ static const char * regname (unsigned int regno, int row) { static char reg[64]; + if (dwarf_regnames && regno < dwarf_regnames_count && dwarf_regnames [regno] != NULL) @@ -6509,8 +6539,6 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg } #define GET(VAR, N) SAFE_BYTE_GET_AND_INC (VAR, start, N, end) -#define LEB() read_uleb128 (start, & length_return, end); start += length_return -#define SLEB() read_sleb128 (start, & length_return, end); start += length_return static unsigned char * read_cie (unsigned char *start, unsigned char *end, @@ -6575,26 +6603,27 @@ read_cie (unsigned char *start, unsigned char *end, fc->ptr_size = eh_addr_size; fc->segment_size = 0; } - fc->code_factor = LEB (); - fc->data_factor = SLEB (); + READ_ULEB (fc->code_factor); + READ_SLEB (fc->data_factor); if (version == 1) { GET (fc->ra, 1); } else { - fc->ra = LEB (); + READ_ULEB (fc->ra); } if (fc->augmentation[0] == 'z') { - augmentation_data_len = LEB (); + READ_ULEB (augmentation_data_len); augmentation_data = start; start += augmentation_data_len; /* PR 17512: file: 11042-2589-0.004. */ if (start > end) { - warn (_("Augmentation data too long: 0x%lx\n"), augmentation_data_len); + warn (_("Augmentation data too long: %#lx, expected at most %#lx\n"), + augmentation_data_len, (long)((end - start) + augmentation_data_len)); return end; } } @@ -6929,7 +6958,7 @@ display_debug_frames (struct dwarf_section *section, if (cie->augmentation[0] == 'z') { - augmentation_data_len = LEB (); + READ_ULEB (augmentation_data_len); augmentation_data = start; start += augmentation_data_len; /* PR 17512: file: 722-8446-0.004. */ @@ -6999,7 +7028,7 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_advance_loc: break; case DW_CFA_offset: - LEB (); + SKIP_ULEB (); if (frame_need_space (fc, opa) >= 0) fc->col_type[opa] = DW_CFA_undefined; break; @@ -7021,41 +7050,44 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_offset_extended: case DW_CFA_val_offset: - reg = LEB (); LEB (); + READ_ULEB (reg); + SKIP_ULEB (); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_restore_extended: - reg = LEB (); + READ_ULEB (reg); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_undefined: - reg = LEB (); + READ_ULEB (reg); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_same_value: - reg = LEB (); + READ_ULEB (reg); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_register: - reg = LEB (); LEB (); + READ_ULEB (reg); + SKIP_ULEB (); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_def_cfa: - LEB (); LEB (); + SKIP_ULEB (); + SKIP_ULEB (); break; case DW_CFA_def_cfa_register: - LEB (); + SKIP_ULEB (); break; case DW_CFA_def_cfa_offset: - LEB (); + SKIP_ULEB (); break; case DW_CFA_def_cfa_expression: - temp = LEB (); + READ_ULEB (temp); new_start = start + temp; if (new_start < start) { @@ -7067,8 +7099,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_expression: case DW_CFA_val_expression: - reg = LEB (); - temp = LEB (); + READ_ULEB (reg); + READ_ULEB (temp); new_start = start + temp; if (new_start < start) { @@ -7083,24 +7115,27 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_offset_extended_sf: case DW_CFA_val_offset_sf: - reg = LEB (); SLEB (); + READ_ULEB (reg); + SKIP_SLEB (); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; case DW_CFA_def_cfa_sf: - LEB (); SLEB (); + SKIP_ULEB (); + SKIP_SLEB (); break; case DW_CFA_def_cfa_offset_sf: - SLEB (); + SKIP_SLEB (); break; case DW_CFA_MIPS_advance_loc8: start += 8; break; case DW_CFA_GNU_args_size: - LEB (); + SKIP_ULEB (); break; case DW_CFA_GNU_negative_offset_extended: - reg = LEB (); LEB (); + READ_ULEB (reg); + SKIP_ULEB (); if (frame_need_space (fc, reg) >= 0) fc->col_type[reg] = DW_CFA_undefined; break; @@ -7120,8 +7155,12 @@ display_debug_frames (struct dwarf_section *section, { unsigned char * tmp; unsigned op, opa; - unsigned long ul, reg, roffs; - dwarf_vma l; + unsigned long ul, roffs; + /* Note: It is tempting to use an unsigned long for 'reg' but there + are various functions, notably frame_space_needed() that assume that + reg is an unsigned int. */ + unsigned int reg; + dwarf_signed_vma l; dwarf_vma ofs; dwarf_vma vma; const char *reg_prefix = ""; @@ -7152,7 +7191,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_offset: - roffs = LEB (); + READ_ULEB (roffs); if (opa >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7239,8 +7278,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_offset_extended: - reg = LEB (); - roffs = LEB (); + READ_ULEB (reg); + READ_ULEB (roffs); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7255,8 +7294,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_val_offset: - reg = LEB (); - roffs = LEB (); + READ_ULEB (reg); + READ_ULEB (roffs); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7271,7 +7310,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_restore_extended: - reg = LEB (); + READ_ULEB (reg); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7293,7 +7332,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_undefined: - reg = LEB (); + READ_ULEB (reg); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7307,7 +7346,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_same_value: - reg = LEB (); + READ_ULEB (reg); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7321,8 +7360,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_register: - reg = LEB (); - roffs = LEB (); + READ_ULEB (reg); + READ_ULEB (roffs); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7385,8 +7424,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa: - fc->cfa_reg = LEB (); - fc->cfa_offset = LEB (); + READ_SLEB (fc->cfa_reg); + READ_ULEB (fc->cfa_offset); fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa: %s ofs %d\n", @@ -7394,7 +7433,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa_register: - fc->cfa_reg = LEB (); + READ_SLEB (fc->cfa_reg); fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_register: %s\n", @@ -7402,7 +7441,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa_offset: - fc->cfa_offset = LEB (); + READ_ULEB (fc->cfa_offset); if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset); break; @@ -7413,7 +7452,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa_expression: - ul = LEB (); + READ_ULEB (ul); if (start >= block_end || ul > (unsigned long) (block_end - start)) { printf (_(" DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul); @@ -7431,8 +7470,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_expression: - reg = LEB (); - ul = LEB (); + READ_ULEB (reg); + READ_ULEB (ul); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; /* PR 17512: file: 069-133014-0.006. */ @@ -7457,8 +7496,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_val_expression: - reg = LEB (); - ul = LEB (); + READ_ULEB (reg); + READ_ULEB (ul); if (reg >= (unsigned int) fc->ncols) reg_prefix = bad_reg; tmp = start + ul; @@ -7481,8 +7520,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_offset_extended_sf: - reg = LEB (); - l = SLEB (); + READ_ULEB (reg); + READ_SLEB (l); if (frame_need_space (fc, reg) < 0) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7497,8 +7536,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_val_offset_sf: - reg = LEB (); - l = SLEB (); + READ_ULEB (reg); + READ_SLEB (l); if (frame_need_space (fc, reg) < 0) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7513,8 +7552,8 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa_sf: - fc->cfa_reg = LEB (); - fc->cfa_offset = SLEB (); + READ_SLEB (fc->cfa_reg); + READ_ULEB (fc->cfa_offset); fc->cfa_offset = fc->cfa_offset * fc->data_factor; fc->cfa_exp = 0; if (! do_debug_frames_interp) @@ -7523,7 +7562,7 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_def_cfa_offset_sf: - fc->cfa_offset = SLEB (); + READ_ULEB (fc->cfa_offset); fc->cfa_offset *= fc->data_factor; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_offset_sf: %d\n", (int) fc->cfa_offset); @@ -7548,14 +7587,15 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_GNU_args_size: - ul = LEB (); + READ_ULEB (ul); if (! do_debug_frames_interp) printf (" DW_CFA_GNU_args_size: %ld\n", ul); break; case DW_CFA_GNU_negative_offset_extended: - reg = LEB (); - l = - LEB (); + READ_ULEB (reg); + READ_SLEB (l); + l = - l; if (frame_need_space (fc, reg) < 0) reg_prefix = bad_reg; if (! do_debug_frames_interp || *reg_prefix != '\0') @@ -7592,8 +7632,6 @@ display_debug_frames (struct dwarf_section *section, } #undef GET -#undef LEB -#undef SLEB static int display_gdb_index (struct dwarf_section *section, |