| From f10bec5ffa487ad3033ed5f38cfd0fc7d696deab Mon Sep 17 00:00:00 2001 |
| From: Nick Clifton <nickc@redhat.com> |
| 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 <pgowda.cve@gmail.com> |
| --- |
| 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 |
| |