From 16c1cd7da0cd159ee2d53c39088564edaf046c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Komar=C4=8Devi=C4=87?= Date: Fri, 16 Jun 2023 17:05:39 +0200 Subject: [PATCH] Fix regression parsing PNG text chunks with zero length payload --- src/pngchunk_int.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/pngchunk_int.cpp b/src/pngchunk_int.cpp index 697a30c63..81fbcd942 100644 --- a/src/pngchunk_int.cpp +++ b/src/pngchunk_int.cpp @@ -100,20 +100,24 @@ DataBuf PngChunk::parseTXTChunk(const DataBuf& data, size_t keysize, TxtChunkTyp } // compressed string after the compression technique spec - const byte* compressedText = data.c_data(keysize + nullSeparators); size_t compressedTextSize = data.size() - keysize - nullSeparators; - enforce(compressedTextSize < data.size(), ErrorCode::kerCorruptedMetadata); + if (compressedTextSize) { + const byte* compressedText = data.c_data(keysize + nullSeparators); + enforce(compressedTextSize < data.size(), ErrorCode::kerCorruptedMetadata); - zlibUncompress(compressedText, static_cast(compressedTextSize), arr); + zlibUncompress(compressedText, static_cast(compressedTextSize), arr); + } } else if (type == tEXt_Chunk) { enforce(data.size() >= Safe::add(keysize, static_cast(1)), ErrorCode::kerCorruptedMetadata); // Extract a non-compressed Latin-1 text chunk // the text comes after the key, but isn't null terminated - const byte* text = data.c_data(keysize + 1); size_t textsize = data.size() - keysize - 1; + if (textsize) { + const byte* text = data.c_data(keysize + 1); - arr = DataBuf(text, textsize); + arr = DataBuf(text, textsize); + } } else if (type == iTXt_Chunk) { enforce(data.size() > Safe::add(keysize, static_cast(3)), ErrorCode::kerCorruptedMetadata); const size_t nullCount = std::count(data.c_data(keysize + 3), data.c_data(data.size() - 1), '\0'); @@ -127,7 +131,8 @@ DataBuf PngChunk::parseTXTChunk(const DataBuf& data, size_t keysize, TxtChunkTyp const byte compressionMethod = data.read_uint8(keysize + 2); enforce(compressionFlag == 0x00 || compressionFlag == 0x01, ErrorCode::kerCorruptedMetadata); - enforce(compressionMethod == 0x00, ErrorCode::kerCorruptedMetadata); + if (compressionFlag == 0x01) + enforce(compressionMethod == 0x00, ErrorCode::kerFailedToReadImageData); // language description string after the compression technique spec const size_t languageTextMaxSize = data.size() - keysize - 3; @@ -141,14 +146,14 @@ DataBuf PngChunk::parseTXTChunk(const DataBuf& data, size_t keysize, TxtChunkTyp data.size() - (keysize + 3 + languageTextSize + 1)); const size_t translatedKeyTextSize = translatedKeyText.size(); - if ((compressionFlag == 0x00) || (compressionFlag == 0x01 && compressionMethod == 0x00)) { - enforce(Safe::add(keysize + 3 + languageTextSize + 1, Safe::add(translatedKeyTextSize, static_cast(1))) <= - data.size(), - ErrorCode::kerCorruptedMetadata); + enforce(Safe::add(keysize + 3 + languageTextSize + 1, Safe::add(translatedKeyTextSize, static_cast(1))) <= + data.size(), + ErrorCode::kerCorruptedMetadata); + const auto textsize = + static_cast(data.size() - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1)); + if (textsize) { const byte* text = data.c_data(keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1); - const auto textsize = - static_cast(data.size() - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1)); if (compressionFlag == 0x00) { // then it's an uncompressed iTXt chunk @@ -156,7 +161,7 @@ DataBuf PngChunk::parseTXTChunk(const DataBuf& data, size_t keysize, TxtChunkTyp std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n"; #endif arr = DataBuf(text, textsize); - } else if (compressionFlag == 0x01 && compressionMethod == 0x00) { + } else { // then it's a zlib compressed iTXt chunk #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n"; @@ -165,12 +170,6 @@ DataBuf PngChunk::parseTXTChunk(const DataBuf& data, size_t keysize, TxtChunkTyp // the compressed text comes after the translated keyword, but isn't null terminated zlibUncompress(text, textsize, arr); } - } else { - // then it isn't zlib compressed and we are sunk -#ifdef EXIV2_DEBUG_MESSAGES - std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.\n"; -#endif - throw Error(ErrorCode::kerFailedToReadImageData); } } else { #ifdef DEBUG