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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
From e1744e11b1c2b36f91a8847b61bafb8c5e7407ae Mon Sep 17 00:00:00 2001
From: nickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Fri, 7 Dec 2018 10:33:30 +0000
Subject: [PATCH] Add a recursion limit to libiberty's demangling code. The
limit is enabled by default, but can be disabled via a new demangling option.
include * demangle.h (DMGL_NO_RECURSE_LIMIT): Define.
(DEMANGLE_RECURSION_LIMIT): Define
PR 87681
PR 87675
PR 87636
PR 87350
PR 87335
libiberty * cp-demangle.h (struct d_info): Add recursion_level field.
* cp-demangle.c (d_function_type): Add recursion counter.
If the recursion limit is reached and the check is not disabled,
then return with a failure result.
(cplus_demangle_init_info): Initialise the recursion_level field.
(d_demangle_callback): If the recursion limit is enabled, check
for a mangled string that is so long that there is not enough
stack space for the local arrays.
* cplus-dem.c (struct work): Add recursion_level field.
(squangle_mop_up): Set the numb and numk fields to zero.
(work_stuff_copy_to_from): Handle the case where a btypevec or
ktypevec field is NULL.
(demangle_nested_args): Add recursion counter. If
the recursion limit is not disabled and reached, return with a
failure result.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@266886 138bc75d-0d04-0410-961f-82ee72b054a4
CVE: CVE-2018-18484
Upstream-Status: Backport [https://github.com/gcc-mirror/gcc/commit/03e51746ed98d9106803f6009ebd71ea670ad3b9]
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
include/ChangeLog | 5 +++++
include/demangle.h | 11 +++++++++++
libiberty/ChangeLog | 23 ++++++++++++++++++++++
libiberty/cp-demangle.c | 51 ++++++++++++++++++++++++++++++++++++++-----------
libiberty/cp-demangle.h | 3 +++
libiberty/cplus-dem.c | 37 +++++++++++++++++++++++++++++++++--
6 files changed, 117 insertions(+), 13 deletions(-)
diff --git a/include/ChangeLog b/include/ChangeLog
index 02ab336..88b0648 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -2,6 +2,11 @@
* GCC 8.3.0 released.
+2018-12-07 Nick Clifton <nickc@redhat.com>
+
+ * demangle.h (DMGL_NO_RECURSE_LIMIT): Define.
+ (DEMANGLE_RECURSION_LIMIT): Define
+
2018-07-26 Release Manager
* GCC 8.2.0 released.
diff --git a/include/demangle.h b/include/demangle.h
index b8d57cf..9bb8a19 100644
--- a/include/demangle.h
+++ b/include/demangle.h
@@ -68,6 +68,17 @@ extern "C" {
/* If none of these are set, use 'current_demangling_style' as the default. */
#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST)
+/* Disable a limit on the depth of recursion in mangled strings.
+ Note if this limit is disabled then stack exhaustion is possible when
+ demangling pathologically complicated strings. Bug reports about stack
+ exhaustion when the option is enabled will be rejected. */
+#define DMGL_NO_RECURSE_LIMIT (1 << 18)
+
+/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as
+ the maximum depth of recursion allowed. It should be enough for any
+ real-world mangled name. */
+#define DEMANGLE_RECURSION_LIMIT 1024
+
/* Enumeration of possible demangling styles.
Lucid and ARM styles are still kept logically distinct, even though
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 1dd05da..2f77038 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -9,6 +9,29 @@
(simple_object_copy_lto_debug_sections): Create file in binary
mode.
+2018-12-07 Nick Clifton <nickc@redhat.com>
+
+ PR 87681
+ PR 87675
+ PR 87636
+ PR 87350
+ PR 87335
+ * cp-demangle.h (struct d_info): Add recursion_level field.
+ * cp-demangle.c (d_function_type): Add recursion counter.
+ If the recursion limit is reached and the check is not disabled,
+ then return with a failure result.
+ (cplus_demangle_init_info): Initialise the recursion_level field.
+ (d_demangle_callback): If the recursion limit is enabled, check
+ for a mangled string that is so long that there is not enough
+ stack space for the local arrays.
+ * cplus-dem.c (struct work): Add recursion_level field.
+ (squangle_mop_up): Set the numb and numk fields to zero.
+ (work_stuff_copy_to_from): Handle the case where a btypevec or
+ ktypevec field is NULL.
+ (demangle_nested_args): Add recursion counter. If
+ the recursion limit is not disabled and reached, return with a
+ failure result.
+
2018-07-26 Release Manager
* GCC 8.2.0 released.
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 3f2a097..c374e46 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -2843,21 +2843,35 @@ d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
static struct demangle_component *
d_function_type (struct d_info *di)
{
- struct demangle_component *ret;
+ struct demangle_component *ret = NULL;
- if (! d_check_char (di, 'F'))
- return NULL;
- if (d_peek_char (di) == 'Y')
+ if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0)
{
- /* Function has C linkage. We don't print this information.
- FIXME: We should print it in verbose mode. */
- d_advance (di, 1);
+ if (di->recursion_level > DEMANGLE_RECURSION_LIMIT)
+ /* FIXME: There ought to be a way to report
+ that the recursion limit has been reached. */
+ return NULL;
+
+ di->recursion_level ++;
}
- ret = d_bare_function_type (di, 1);
- ret = d_ref_qualifier (di, ret);
- if (! d_check_char (di, 'E'))
- return NULL;
+ if (d_check_char (di, 'F'))
+ {
+ if (d_peek_char (di) == 'Y')
+ {
+ /* Function has C linkage. We don't print this information.
+ FIXME: We should print it in verbose mode. */
+ d_advance (di, 1);
+ }
+ ret = d_bare_function_type (di, 1);
+ ret = d_ref_qualifier (di, ret);
+
+ if (! d_check_char (di, 'E'))
+ ret = NULL;
+ }
+
+ if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0)
+ di->recursion_level --;
return ret;
}
@@ -6188,6 +6202,7 @@ cplus_demangle_init_info (const char *mangled, int options, size_t len,
di->expansion = 0;
di->is_expression = 0;
di->is_conversion = 0;
+ di->recursion_level = 0;
}
/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI
@@ -6227,6 +6242,20 @@ d_demangle_callback (const char *mangled, int options,
cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
+ /* PR 87675 - Check for a mangled string that is so long
+ that we do not have enough stack space to demangle it. */
+ if (((options & DMGL_NO_RECURSE_LIMIT) == 0)
+ /* This check is a bit arbitrary, since what we really want to do is to
+ compare the sizes of the di.comps and di.subs arrays against the
+ amount of stack space remaining. But there is no portable way to do
+ this, so instead we use the recursion limit as a guide to the maximum
+ size of the arrays. */
+ && (unsigned long) di.num_comps > DEMANGLE_RECURSION_LIMIT)
+ {
+ /* FIXME: We need a way to indicate that a stack limit has been reached. */
+ return 0;
+ }
+
{
#ifdef CP_DYNAMIC_ARRAYS
__extension__ struct demangle_component comps[di.num_comps];
diff --git a/libiberty/cp-demangle.h b/libiberty/cp-demangle.h
index 51b8a24..d87a830 100644
--- a/libiberty/cp-demangle.h
+++ b/libiberty/cp-demangle.h
@@ -122,6 +122,9 @@ struct d_info
/* Non-zero if we are parsing the type operand of a conversion
operator, but not when in an expression. */
int is_conversion;
+ /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
+ the current recursion level. */
+ unsigned int recursion_level;
};
/* To avoid running past the ending '\0', don't:
diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
index 6d58bd8..8b9646f 100644
--- a/libiberty/cplus-dem.c
+++ b/libiberty/cplus-dem.c
@@ -146,6 +146,7 @@ struct work_stuff
int *proctypevec; /* Indices of currently processed remembered typevecs. */
int proctypevec_size;
int nproctypes;
+ unsigned int recursion_level;
};
#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -1292,12 +1293,14 @@ squangle_mop_up (struct work_stuff *work)
free ((char *) work -> btypevec);
work->btypevec = NULL;
work->bsize = 0;
+ work->numb = 0;
}
if (work -> ktypevec != NULL)
{
free ((char *) work -> ktypevec);
work->ktypevec = NULL;
work->ksize = 0;
+ work->numk = 0;
}
}
@@ -1331,8 +1334,15 @@ work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
for (i = 0; i < from->numk; i++)
{
- int len = strlen (from->ktypevec[i]) + 1;
+ int len;
+
+ if (from->ktypevec[i] == NULL)
+ {
+ to->ktypevec[i] = NULL;
+ continue;
+ }
+ len = strlen (from->ktypevec[i]) + 1;
to->ktypevec[i] = XNEWVEC (char, len);
memcpy (to->ktypevec[i], from->ktypevec[i], len);
}
@@ -1342,8 +1352,15 @@ work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
for (i = 0; i < from->numb; i++)
{
- int len = strlen (from->btypevec[i]) + 1;
+ int len;
+
+ if (from->btypevec[i] == NULL)
+ {
+ to->btypevec[i] = NULL;
+ continue;
+ }
+ len = strlen (from->btypevec[i]) + 1;
to->btypevec[i] = XNEWVEC (char , len);
memcpy (to->btypevec[i], from->btypevec[i], len);
}
@@ -1401,6 +1418,7 @@ delete_non_B_K_work_stuff (struct work_stuff *work)
free ((char*) work->tmpl_argvec);
work->tmpl_argvec = NULL;
+ work->ntmpl_args = 0;
}
if (work->previous_argument)
{
@@ -4477,6 +4495,7 @@ remember_Btype (struct work_stuff *work, const char *start,
}
/* Lose all the info related to B and K type codes. */
+
static void
forget_B_and_K_types (struct work_stuff *work)
{
@@ -4502,6 +4521,7 @@ forget_B_and_K_types (struct work_stuff *work)
}
}
}
+
/* Forget the remembered types, but not the type vector itself. */
static void
@@ -4696,6 +4716,16 @@ demangle_nested_args (struct work_stuff *work, const char **mangled,
int result;
int saved_nrepeats;
+ if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0)
+ {
+ if (work->recursion_level > DEMANGLE_RECURSION_LIMIT)
+ /* FIXME: There ought to be a way to report
+ that the recursion limit has been reached. */
+ return 0;
+
+ work->recursion_level ++;
+ }
+
/* The G++ name-mangling algorithm does not remember types on nested
argument lists, unless -fsquangling is used, and in that case the
type vector updated by remember_type is not used. So, we turn
@@ -4722,6 +4752,9 @@ demangle_nested_args (struct work_stuff *work, const char **mangled,
--work->forgetting_types;
work->nrepeats = saved_nrepeats;
+ if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0)
+ --work->recursion_level;
+
return result;
}
--
2.7.4
|