diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 40611e56ff4..de3a6eeef52 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,15 @@ +2022-01-31 Nick Clifton + + PR 98886 + PR 99935 + * rust-demangle.c (struct rust_demangler): Add a recursion + counter. + (demangle_path): Increment/decrement the recursion counter upon + entry and exit. Fail if the counter exceeds a fixed limit. + (demangle_type): Likewise. + (rust_demangle_callback): Initialise the recursion counter, + disabling if requested by the option flags. + 2022-01-15 Martin Sebor * regex.c: Suppress -Wuse-after-free. diff --git a/libiberty/rust-demangle.c b/libiberty/rust-demangle.c index 18c760491bd..3b24d63892a 100644 --- a/libiberty/rust-demangle.c +++ b/libiberty/rust-demangle.c @@ -74,6 +74,12 @@ struct rust_demangler /* Rust mangling version, with legacy mangling being -1. */ int version; + /* Recursion depth. */ + unsigned int recursion; + /* Maximum number of times demangle_path may be called recursively. */ +#define RUST_MAX_RECURSION_COUNT 1024 +#define RUST_NO_RECURSION_LIMIT ((unsigned int) -1) + uint64_t bound_lifetime_depth; }; @@ -671,6 +677,15 @@ demangle_path (struct rust_demangler *rdm, int in_value) if (rdm->errored) return; + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + goto fail_return; + } + switch (tag = next (rdm)) { case 'C': @@ -688,10 +703,7 @@ demangle_path (struct rust_demangler *rdm, int in_value) case 'N': ns = next (rdm); if (!ISLOWER (ns) && !ISUPPER (ns)) - { - rdm->errored = 1; - return; - } + goto fail_return; demangle_path (rdm, in_value); @@ -776,9 +788,15 @@ demangle_path (struct rust_demangler *rdm, int in_value) } break; default: - rdm->errored = 1; - return; + goto fail_return; } + goto pass_return; + + fail_return: + rdm->errored = 1; + pass_return: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; } static void @@ -870,6 +888,19 @@ demangle_type (struct rust_demangler *rdm) return; } + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + { + rdm->errored = 1; + -- rdm->recursion; + return; + } + } + switch (tag) { case 'R': @@ -1030,6 +1061,9 @@ demangle_type (struct rust_demangler *rdm) rdm->next--; demangle_path (rdm, 0); } + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; } /* A trait in a trait object may have some "existential projections" @@ -1320,6 +1354,7 @@ rust_demangle_callback (const char *mangled, int options, rdm.skipping_printing = 0; rdm.verbose = (options & DMGL_VERBOSE) != 0; rdm.version = 0; + rdm.recursion = (options & DMGL_NO_RECURSE_LIMIT) ? RUST_NO_RECURSION_LIMIT : 0; rdm.bound_lifetime_depth = 0; /* Rust symbols always start with _R (v0) or _ZN (legacy). */