From 1fc7c994d6232e373fc9f36e72ed9855d4d7cd76 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 12 Dec 2019 07:39:23 -0500
Subject: [PATCH] DRTVWR-494: Fix VS LLError::Log::demangle() vulnerability.

The Windows implementation of demangle() assumed that a "mangled" class name
produced by typeid(class).name() always starts with the prefix "class ",
checked for that and removed it. If the mangled name didn't start with that
prefix, it would emit a debug message and return the full name.

When the class in question is actually a struct, the prefix is "struct "
instead. But when demangle() was being called before logging had been fully
initialized, the debug message remarking that it didn't start with "class "
crashed.

Look for either "class " or "struct " prefix. Remove whichever is found and
return the rest of the name. If neither is found, only log if logging is
available.
---
 indra/llcommon/llerror.cpp | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 335a0995feb..83d380fafdb 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -302,28 +302,35 @@ namespace LLError
 	{
 #ifdef __GNUC__
 		// GCC: type_info::name() returns a mangled class name,st demangle
-        // passing nullptr, 0 forces allocation of a unique buffer we can free
-        // fixing MAINT-8724 on OSX 10.14
+		// passing nullptr, 0 forces allocation of a unique buffer we can free
+		// fixing MAINT-8724 on OSX 10.14
 		int status = -1;
 		char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status);
-        std::string result(name ? name : mangled);
-        free(name);
-        return result;
-#elif LL_WINDOWS
-		// DevStudio: type_info::name() includes the text "class " at the start
+		std::string result(name ? name : mangled);
+		free(name);
+		return result;
 
-		static const std::string class_prefix = "class ";
+#elif LL_WINDOWS
+		// Visual Studio: type_info::name() includes the text "class " at the start
 		std::string name = mangled;
-		if (0 != name.compare(0, class_prefix.length(), class_prefix))
+		for (const auto& prefix : std::vector<std::string>{ "class ", "struct " })
+		{
+			if (0 == name.compare(0, prefix.length(), prefix))
+			{
+				return name.substr(prefix.length());
+			}
+		}
+		// huh, that's odd, we should see one or the other prefix -- but don't
+		// try to log unless logging is already initialized
+		if (is_available())
 		{
-			LL_DEBUGS() << "Did not see '" << class_prefix << "' prefix on '"
-					   << name << "'" << LL_ENDL;
-			return name;
+			// in Python, " or ".join(vector) -- but in C++, a PITB
+			LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '"
+				<< name << "'" << LL_ENDL;
 		}
+		return name;
 
-		return name.substr(class_prefix.length());
-
-#else
+#else  // neither GCC nor Visual Studio
 		return mangled;
 #endif
 	}
-- 
GitLab