1From f10bec5ffa487ad3033ed5f38cfd0fc7d696deab Mon Sep 17 00:00:00 2001 2From: Nick Clifton <nickc@redhat.com> 3Date: Mon, 31 Jan 2022 14:28:42 +0000 4Subject: [PATCH] libiberty: Fix infinite recursion in rust demangler. 5 6libiberty/ 7 PR demangler/98886 8 PR demangler/99935 9 * rust-demangle.c (struct rust_demangler): Add a recursion 10 counter. 11 (demangle_path): Increment/decrement the recursion counter upon 12 entry and exit. Fail if the counter exceeds a fixed limit. 13 (demangle_type): Likewise. 14 (rust_demangle_callback): Initialise the recursion counter, 15 disabling if requested by the option flags. 16 17CVE: CVE-2021-46195 18Upstream-Status: Backport 19[https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=f10bec5ffa487ad3033ed5f38cfd0fc7d696deab] 20Signed-off-by: Pgowda <pgowda.cve@gmail.com> 21--- 22 libiberty/rust-demangle.c | 47 ++++++++++++++++++++++++++++++++++----- 23 1 file changed, 41 insertions(+), 6 deletions(-) 24 25diff --git a/libiberty/rust-demangle.c b/libiberty/rust-demangle.c 26index 18c760491bd..3b24d63892a 100644 27--- a/libiberty/rust-demangle.c 28+++ b/libiberty/rust-demangle.c 29@@ -74,6 +74,12 @@ struct rust_demangler 30 /* Rust mangling version, with legacy mangling being -1. */ 31 int version; 32 33+ /* Recursion depth. */ 34+ unsigned int recursion; 35+ /* Maximum number of times demangle_path may be called recursively. */ 36+#define RUST_MAX_RECURSION_COUNT 1024 37+#define RUST_NO_RECURSION_LIMIT ((unsigned int) -1) 38+ 39 uint64_t bound_lifetime_depth; 40 }; 41 42@@ -671,6 +677,15 @@ demangle_path (struct rust_demangler *rdm, int in_value) 43 if (rdm->errored) 44 return; 45 46+ if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 47+ { 48+ ++ rdm->recursion; 49+ if (rdm->recursion > RUST_MAX_RECURSION_COUNT) 50+ /* FIXME: There ought to be a way to report 51+ that the recursion limit has been reached. */ 52+ goto fail_return; 53+ } 54+ 55 switch (tag = next (rdm)) 56 { 57 case 'C': 58@@ -688,10 +703,7 @@ demangle_path (struct rust_demangler *rdm, int in_value) 59 case 'N': 60 ns = next (rdm); 61 if (!ISLOWER (ns) && !ISUPPER (ns)) 62- { 63- rdm->errored = 1; 64- return; 65- } 66+ goto fail_return; 67 68 demangle_path (rdm, in_value); 69 70@@ -776,9 +788,15 @@ demangle_path (struct rust_demangler *rdm, int in_value) 71 } 72 break; 73 default: 74- rdm->errored = 1; 75- return; 76+ goto fail_return; 77 } 78+ goto pass_return; 79+ 80+ fail_return: 81+ rdm->errored = 1; 82+ pass_return: 83+ if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 84+ -- rdm->recursion; 85 } 86 87 static void 88@@ -870,6 +888,19 @@ demangle_type (struct rust_demangler *rdm) 89 return; 90 } 91 92+ if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 93+ { 94+ ++ rdm->recursion; 95+ if (rdm->recursion > RUST_MAX_RECURSION_COUNT) 96+ /* FIXME: There ought to be a way to report 97+ that the recursion limit has been reached. */ 98+ { 99+ rdm->errored = 1; 100+ -- rdm->recursion; 101+ return; 102+ } 103+ } 104+ 105 switch (tag) 106 { 107 case 'R': 108@@ -1030,6 +1061,9 @@ demangle_type (struct rust_demangler *rdm) 109 rdm->next--; 110 demangle_path (rdm, 0); 111 } 112+ 113+ if (rdm->recursion != RUST_NO_RECURSION_LIMIT) 114+ -- rdm->recursion; 115 } 116 117 /* A trait in a trait object may have some "existential projections" 118@@ -1320,6 +1354,7 @@ rust_demangle_callback (const char *mangled, int options, 119 rdm.skipping_printing = 0; 120 rdm.verbose = (options & DMGL_VERBOSE) != 0; 121 rdm.version = 0; 122+ rdm.recursion = (options & DMGL_NO_RECURSE_LIMIT) ? RUST_NO_RECURSION_LIMIT : 0; 123 rdm.bound_lifetime_depth = 0; 124 125 /* Rust symbols always start with _R (v0) or _ZN (legacy). */ 126-- 1272.27.0 128 129