From bf95260f37736202e500597d9770662cc1cb1720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Wed, 3 Mar 2021 12:59:18 +0100 Subject: [PATCH] Fix issues found in SawyerChunk decoder --- src/openrct2/rct12/SawyerChunkReader.cpp | 36 ++++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/openrct2/rct12/SawyerChunkReader.cpp b/src/openrct2/rct12/SawyerChunkReader.cpp index 81339d93fa..5ac60f2aff 100644 --- a/src/openrct2/rct12/SawyerChunkReader.cpp +++ b/src/openrct2/rct12/SawyerChunkReader.cpp @@ -84,13 +84,22 @@ std::shared_ptr SawyerChunkReader::ReadChunk() } auto buffer = static_cast(AllocateLargeTempBuffer()); - size_t uncompressedLength = DecodeChunk(buffer, MAX_UNCOMPRESSED_CHUNK_SIZE, compressedData.get(), header); - if (uncompressedLength == 0) + try { - throw SawyerChunkException(EXCEPTION_MSG_ZERO_SIZED_CHUNK); + size_t uncompressedLength = DecodeChunk(buffer, MAX_UNCOMPRESSED_CHUNK_SIZE, compressedData.get(), header); + if (uncompressedLength == 0) + { + throw SawyerChunkException(EXCEPTION_MSG_ZERO_SIZED_CHUNK); + } + buffer = static_cast(FinaliseLargeTempBuffer(buffer, uncompressedLength)); + return std::make_shared( + static_cast(header.encoding), buffer, uncompressedLength); + } + catch (const std::exception&) + { + FreeLargeTempBuffer(buffer); + throw; } - buffer = static_cast(FinaliseLargeTempBuffer(buffer, uncompressedLength)); - return std::make_shared(static_cast(header.encoding), buffer, uncompressedLength); } default: throw SawyerChunkException(EXCEPTION_MSG_INVALID_CHUNK_ENCODING); @@ -192,10 +201,10 @@ size_t SawyerChunkReader::DecodeChunk(void* dst, size_t dstCapacity, const void* size_t SawyerChunkReader::DecodeChunkRLERepeat(void* dst, size_t dstCapacity, const void* src, size_t srcLength) { - auto immBuffer = AllocateLargeTempBuffer(); - auto immLength = DecodeChunkRLE(immBuffer, MAX_UNCOMPRESSED_CHUNK_SIZE, src, srcLength); - auto size = DecodeChunkRepeat(dst, dstCapacity, immBuffer, immLength); - FreeLargeTempBuffer(immBuffer); + auto immBuffer = std::unique_ptr( + static_cast(AllocateLargeTempBuffer()), &FreeLargeTempBuffer); + auto immLength = DecodeChunkRLE(immBuffer.get(), MAX_UNCOMPRESSED_CHUNK_SIZE, src, srcLength); + auto size = DecodeChunkRepeat(dst, dstCapacity, immBuffer.get(), immLength); return size; } @@ -267,6 +276,15 @@ size_t SawyerChunkReader::DecodeChunkRepeat(void* dst, size_t dstCapacity, const { throw SawyerChunkException(EXCEPTION_MSG_DESTINATION_TOO_SMALL); } + if (copySrc < dst) + { + throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE); + } + if ((copySrc < (dst8 + count) && copySrc >= dst8) + || ((copySrc + count) <= (dst8 + count) && (copySrc + count) > dst8)) + { + throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE); + } std::memcpy(dst8, copySrc, count); dst8 += count;