1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
From 16c1cd7da0cd159ee2d53c39088564edaf046c77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milo=C5=A1=20Komar=C4=8Devi=C4=87?=
<miloskomarcevic@aim.com>
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 697a30c63c..81fbcd942d 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<uint32_t>(compressedTextSize), arr);
+ zlibUncompress(compressedText, static_cast<uint32_t>(compressedTextSize), arr);
+ }
} else if (type == tEXt_Chunk) {
enforce(data.size() >= Safe::add(keysize, static_cast<size_t>(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<size_t>(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<size_t>(1))) <=
- data.size(),
- ErrorCode::kerCorruptedMetadata);
+ enforce(Safe::add(keysize + 3 + languageTextSize + 1, Safe::add(translatedKeyTextSize, static_cast<size_t>(1))) <=
+ data.size(),
+ ErrorCode::kerCorruptedMetadata);
+ const auto textsize =
+ static_cast<long>(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<long>(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
|