Nick Clifton
2018-11-29 15:01:06 UTC
Hi Ian,
Libiberty's demangler seems to be a favourite target of people looking
to file new CVEs by fuzzing strings and I have finally gotten tired of
reviewing them all. So I would like to propose a patch to add support
for placing a recursion limit on the demangling functions.
The patch adds a new demangling option - DMGL_RECURSE_LIMIT - which
needs to be present in order for the new code to take affect. So
current users of the libiberty library will not be affected[*].
The patch also adds a new function - cplus_demangle_set_recursion_limit()
- which can be used to probe and/or set the limit.
When the option is in effect a few of the demangler functions will use
static counters to make sure that they have not been called
recursively too many times. I only chose those functions for which I
could find filed PRs that triggered this kind of problem. But with
the stack limiting framework in place it would be easy to add checks
to other functions, should they prove necessary.
I also encountered one binary that could trigger stack exhaustion in
d_demangle_callback where it tries to allocate stack space to hold
component and substitution arrays. So the patch includes a check
for this situation as well.
There does not appear to be any error reporting framework for the
demangler functions, so when a recursion limit is reached the
functions just return a failure/NULL result.
I have tested the patch with a variety of different binutils builds
and also bootstrapped an x86_64-pc-linux-gnu toolchain. No new
failures were found.
What do you think, is this approach reasonable ?
Cheers
Nick
[*] Actually I also have a patch for the binutils to modify the
addr2line, c++filt, nm and objdump programs to make use of this new
feature, should it be accepted into libiberty.
Patches:
include/ChangeLog
2018-11-29 Nick Clifton <***@redhat.com>
* demangle.h (DMGL_RECURSE_LIMIT): Define.
(cplus_demangle_set_recursion_limit): Prototype.
libiberty/ChangeLog
2018-11-29 Nick Clifton <***@redhat.com>
PR 87675
PR 87636
* cp-demangle.c (demangle_recursion_limit): New static
variable.
(d_function_type): Add recursion counter. If the recursion
limit is enabled and reached, return with a failure result.
(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_demangle_set_recursion): New function. Sets and/or
returns the current stack recursion limit.
* cplus-dem.c (demangle_nested_args): Add recursion counter. If
the recursion limit is enabled and reached, return with a
failure result.
Libiberty's demangler seems to be a favourite target of people looking
to file new CVEs by fuzzing strings and I have finally gotten tired of
reviewing them all. So I would like to propose a patch to add support
for placing a recursion limit on the demangling functions.
The patch adds a new demangling option - DMGL_RECURSE_LIMIT - which
needs to be present in order for the new code to take affect. So
current users of the libiberty library will not be affected[*].
The patch also adds a new function - cplus_demangle_set_recursion_limit()
- which can be used to probe and/or set the limit.
When the option is in effect a few of the demangler functions will use
static counters to make sure that they have not been called
recursively too many times. I only chose those functions for which I
could find filed PRs that triggered this kind of problem. But with
the stack limiting framework in place it would be easy to add checks
to other functions, should they prove necessary.
I also encountered one binary that could trigger stack exhaustion in
d_demangle_callback where it tries to allocate stack space to hold
component and substitution arrays. So the patch includes a check
for this situation as well.
There does not appear to be any error reporting framework for the
demangler functions, so when a recursion limit is reached the
functions just return a failure/NULL result.
I have tested the patch with a variety of different binutils builds
and also bootstrapped an x86_64-pc-linux-gnu toolchain. No new
failures were found.
What do you think, is this approach reasonable ?
Cheers
Nick
[*] Actually I also have a patch for the binutils to modify the
addr2line, c++filt, nm and objdump programs to make use of this new
feature, should it be accepted into libiberty.
Patches:
include/ChangeLog
2018-11-29 Nick Clifton <***@redhat.com>
* demangle.h (DMGL_RECURSE_LIMIT): Define.
(cplus_demangle_set_recursion_limit): Prototype.
libiberty/ChangeLog
2018-11-29 Nick Clifton <***@redhat.com>
PR 87675
PR 87636
* cp-demangle.c (demangle_recursion_limit): New static
variable.
(d_function_type): Add recursion counter. If the recursion
limit is enabled and reached, return with a failure result.
(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_demangle_set_recursion): New function. Sets and/or
returns the current stack recursion limit.
* cplus-dem.c (demangle_nested_args): Add recursion counter. If
the recursion limit is enabled and reached, return with a
failure result.