From f10bec5ffa487ad3033ed5f38cfd0fc7d696deab Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 31 Jan 2022 14:28:42 +0000 Subject: [PATCH] libiberty: Fix infinite recursion in rust demangler. libiberty/ PR demangler/98886 PR demangler/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. CVE: CVE-2021-46195 Upstream-Status: Backport [https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=f10bec5ffa487ad3033ed5f38cfd0fc7d696deab] Signed-off-by: Pgowda --- libiberty/rust-demangle.c | 47 ++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) 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). */ -- 2.27.0