1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
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
|