| From d949ff5607b9f595e0eed2ff15fbe5eb84eb3a34 Mon Sep 17 00:00:00 2001 |
| From: Nick Clifton <nickc@redhat.com> |
| Date: Fri, 28 Apr 2017 10:28:04 +0100 |
| Subject: [PATCH] Fix heap-buffer overflow bugs caused when dumping debug |
| information from a corrupt binary. |
| |
| PR binutils/21438 |
| * dwarf.c (process_extended_line_op): Do not assume that the |
| string extracted from the section is NUL terminated. |
| (fetch_indirect_string): If the string retrieved from the section |
| is not NUL terminated, return an error message. |
| (fetch_indirect_line_string): Likewise. |
| (fetch_indexed_string): Likewise. |
| |
| Upstream-Status: Backport |
| CVE: CVE-2017-8398 |
| Signed-off-by: Armin Kuster <akuster@mvista.com> |
| |
| --- |
| binutils/ChangeLog | 10 +++++++++ |
| binutils/dwarf.c | 66 +++++++++++++++++++++++++++++++++++++++++------------- |
| 2 files changed, 60 insertions(+), 16 deletions(-) |
| |
| Index: git/binutils/dwarf.c |
| =================================================================== |
| --- git.orig/binutils/dwarf.c |
| +++ git/binutils/dwarf.c |
| @@ -472,15 +472,20 @@ process_extended_line_op (unsigned char |
| printf (_(" Entry\tDir\tTime\tSize\tName\n")); |
| printf (" %d\t", ++state_machine_regs.last_file_entry); |
| |
| - name = data; |
| - data += strnlen ((char *) data, end - data) + 1; |
| - printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); |
| - data += bytes_read; |
| - printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); |
| - data += bytes_read; |
| - printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); |
| - data += bytes_read; |
| - printf ("%s\n\n", name); |
| + { |
| + size_t l; |
| + |
| + name = data; |
| + l = strnlen ((char *) data, end - data); |
| + data += len + 1; |
| + printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); |
| + data += bytes_read; |
| + printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); |
| + data += bytes_read; |
| + printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); |
| + data += bytes_read; |
| + printf ("%.*s\n\n", (int) l, name); |
| + } |
| |
| if (((unsigned int) (data - orig_data) != len) || data == end) |
| warn (_("DW_LNE_define_file: Bad opcode length\n")); |
| @@ -597,18 +602,27 @@ static const unsigned char * |
| fetch_indirect_string (dwarf_vma offset) |
| { |
| struct dwarf_section *section = &debug_displays [str].section; |
| + const unsigned char * ret; |
| |
| if (section->start == NULL) |
| return (const unsigned char *) _("<no .debug_str section>"); |
| |
| - if (offset > section->size) |
| + if (offset >= section->size) |
| { |
| warn (_("DW_FORM_strp offset too big: %s\n"), |
| dwarf_vmatoa ("x", offset)); |
| return (const unsigned char *) _("<offset is too big>"); |
| } |
| + ret = section->start + offset; |
| + /* Unfortunately we cannot rely upon the .debug_str section ending with a |
| + NUL byte. Since our caller is expecting to receive a well formed C |
| + string we test for the lack of a terminating byte here. */ |
| + if (strnlen ((const char *) ret, section->size - offset) |
| + == section->size - offset) |
| + ret = (const unsigned char *) |
| + _("<no NUL byte at end of .debug_str section>"); |
| |
| - return (const unsigned char *) section->start + offset; |
| + return ret; |
| } |
| |
| static const char * |
| @@ -621,6 +635,7 @@ fetch_indexed_string (dwarf_vma idx, str |
| struct dwarf_section *str_section = &debug_displays [str_sec_idx].section; |
| dwarf_vma index_offset = idx * offset_size; |
| dwarf_vma str_offset; |
| + const char * ret; |
| |
| if (index_section->start == NULL) |
| return (dwo ? _("<no .debug_str_offsets.dwo section>") |
| @@ -628,7 +643,7 @@ fetch_indexed_string (dwarf_vma idx, str |
| |
| if (this_set != NULL) |
| index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS]; |
| - if (index_offset > index_section->size) |
| + if (index_offset >= index_section->size) |
| { |
| warn (_("DW_FORM_GNU_str_index offset too big: %s\n"), |
| dwarf_vmatoa ("x", index_offset)); |
| @@ -641,14 +656,22 @@ fetch_indexed_string (dwarf_vma idx, str |
| |
| str_offset = byte_get (index_section->start + index_offset, offset_size); |
| str_offset -= str_section->address; |
| - if (str_offset > str_section->size) |
| + if (str_offset >= str_section->size) |
| { |
| warn (_("DW_FORM_GNU_str_index indirect offset too big: %s\n"), |
| dwarf_vmatoa ("x", str_offset)); |
| return _("<indirect index offset is too big>"); |
| } |
| |
| - return (const char *) str_section->start + str_offset; |
| + ret = (const char *) str_section->start + str_offset; |
| + /* Unfortunately we cannot rely upon str_section ending with a NUL byte. |
| + Since our caller is expecting to receive a well formed C string we test |
| + for the lack of a terminating byte here. */ |
| + if (strnlen (ret, str_section->size - str_offset) |
| + == str_section->size - str_offset) |
| + ret = (const char *) _("<no NUL byte at end of section>"); |
| + |
| + return ret; |
| } |
| |
| static const char * |
| Index: git/binutils/ChangeLog |
| =================================================================== |
| --- git.orig/binutils/ChangeLog |
| +++ git/binutils/ChangeLog |
| @@ -1,3 +1,13 @@ |
| +2017-04-28 Nick Clifton <nickc@redhat.com> |
| + |
| + PR binutils/21438 |
| + * dwarf.c (process_extended_line_op): Do not assume that the |
| + string extracted from the section is NUL terminated. |
| + (fetch_indirect_string): If the string retrieved from the section |
| + is not NUL terminated, return an error message. |
| + (fetch_indirect_line_string): Likewise. |
| + (fetch_indexed_string): Likewise. |
| + |
| 2017-02-14 Nick Clifton <nickc@redhat.com> |
| |
| PR binutils/21157 |