From f35c744d5af3dfc4449bd0babc5225f1e631995c Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Thu, 19 Mar 2020 15:07:31 -0400
Subject: [PATCH] Fix a potential use after free and null deref in LLSD unzip
 routines

---
 indra/llcommon/llsdserialize.cpp | 43 ++++++++++++++++----------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index c3fb4ebc2ca..1ae7a6f4788 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -2153,13 +2153,16 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 	z_stream strm;
 		
 	const U32 CHUNK = 65536;
-
-	U8 *in = new(std::nothrow) U8[size];
-	if (!in)
+	std::unique_ptr<U8[]> in;
+	try
+	{
+		in = std::make_unique<U8[]>(size);
+	}
+	catch(const std::bad_alloc&)
 	{
 		return ZR_MEM_ERROR;
 	}
-	is.read((char*) in, size); 
+	is.read((char*) in.get(), size); 
 
 	U8 out[CHUNK];
 		
@@ -2167,7 +2170,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 	strm.zfree = Z_NULL;
 	strm.opaque = Z_NULL;
 	strm.avail_in = size;
-	strm.next_in = in;
+	strm.next_in = in.get();
 
 	S32 ret = inflateInit(&strm);
 	
@@ -2180,7 +2183,6 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 		{
 			inflateEnd(&strm);
 			free(result);
-			delete [] in;
 			return ZR_DATA_ERROR;
 		}
 		
@@ -2192,9 +2194,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 		case Z_MEM_ERROR:
 			inflateEnd(&strm);
 			free(result);
-			delete [] in;
 			return ZR_MEM_ERROR;
-			break;
 		}
 
 		U32 have = CHUNK-strm.avail_out;
@@ -2207,7 +2207,6 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 			{
 				free(result);
 			}
-			delete[] in;
 			return ZR_MEM_ERROR;
 		}
 		result = new_result;
@@ -2217,7 +2216,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 	} while (ret == Z_OK);
 
 	inflateEnd(&strm);
-	delete [] in;
+	in.reset();
 
 	if (ret != Z_STREAM_END)
 	{
@@ -2284,13 +2283,18 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
 		
 	const U32 CHUNK = 0x4000;
 
-	U8 *in = new(std::nothrow) U8[size];
-	if (in == NULL)
+	std::unique_ptr<U8[]> in;
+	try
+	{
+		in = std::make_unique<U8[]>(size);
+	}
+	catch (const std::bad_alloc&)
 	{
 		LL_WARNS() << "Memory allocation failure." << LL_ENDL;
-		return NULL;
+		return nullptr;
 	}
-	is.read((char*) in, size); 
+
+	is.read((char*) in.get(), size); 
 
 	U8 out[CHUNK];
 		
@@ -2298,7 +2302,7 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
 	strm.zfree = Z_NULL;
 	strm.opaque = Z_NULL;
 	strm.avail_in = size;
-	strm.next_in = in;
+	strm.next_in = in.get();
 
 	
 	S32 ret = inflateInit2(&strm,  windowBits | ENABLE_ZLIB_GZIP );
@@ -2311,8 +2315,7 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
 		{
 			inflateEnd(&strm);
 			free(result);
-			delete [] in;
-			valid = false;
+			return NULL;
 		}
 		
 		switch (ret)
@@ -2323,9 +2326,8 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
 		case Z_MEM_ERROR:
 			inflateEnd(&strm);
 			free(result);
-			delete [] in;
 			valid = false;
-			break;
+			return NULL;
 		}
 
 		U32 have = CHUNK-strm.avail_out;
@@ -2342,7 +2344,6 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
 			{
 				free(result);
 			}
-			delete[] in;
 			valid = false;
 			return NULL;
 		}
@@ -2353,7 +2354,7 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32
 	} while (ret == Z_OK);
 
 	inflateEnd(&strm);
-	delete [] in;
+	in.reset();
 
 	if (ret != Z_STREAM_END)
 	{
-- 
GitLab