Skip to content

Commit 89face0

Browse files
Merge pull request #3081 from SixLabors/bp/fixIssue3079
Add checks, if enough data is present when reading PNG text chunks
2 parents 533ed51 + 8d78fe0 commit 89face0

File tree

2 files changed

+89
-5
lines changed

2 files changed

+89
-5
lines changed

src/ImageSharp/Formats/Png/PngDecoderCore.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,26 +1402,31 @@ private void ReadCompressedTextChunk(ImageMetadata baseMetadata, PngMetadata met
14021402
return;
14031403
}
14041404

1405-
int zeroIndex = data.IndexOf((byte)0);
1406-
if (zeroIndex is < PngConstants.MinTextKeywordLength or > PngConstants.MaxTextKeywordLength)
1405+
int keywordEnd = data.IndexOf((byte)0);
1406+
if (keywordEnd is < PngConstants.MinTextKeywordLength or > PngConstants.MaxTextKeywordLength)
14071407
{
14081408
return;
14091409
}
14101410

1411-
byte compressionMethod = data[zeroIndex + 1];
1411+
if (keywordEnd < 0 || keywordEnd + 2 > data.Length)
1412+
{
1413+
return; // Not enough data for keyword + null + compression method.
1414+
}
1415+
1416+
byte compressionMethod = data[keywordEnd + 1];
14121417
if (compressionMethod != 0)
14131418
{
14141419
// Only compression method 0 is supported (zlib datastream with deflate compression).
14151420
return;
14161421
}
14171422

1418-
ReadOnlySpan<byte> keywordBytes = data[..zeroIndex];
1423+
ReadOnlySpan<byte> keywordBytes = data[..keywordEnd];
14191424
if (!TryReadTextKeyword(keywordBytes, out string name))
14201425
{
14211426
return;
14221427
}
14231428

1424-
ReadOnlySpan<byte> compressedData = data[(zeroIndex + 2)..];
1429+
ReadOnlySpan<byte> compressedData = data[(keywordEnd + 2)..];
14251430

14261431
if (this.TryDecompressTextData(compressedData, PngConstants.Encoding, out string? uncompressed)
14271432
&& !TryReadTextChunkMetadata(baseMetadata, name, uncompressed))
@@ -1932,6 +1937,11 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
19321937
return;
19331938
}
19341939

1940+
if (zeroIndexKeyword < 0 || zeroIndexKeyword + 4 > data.Length)
1941+
{
1942+
return; // Not enough data for keyword + null + flag + method + language.
1943+
}
1944+
19351945
byte compressionFlag = data[zeroIndexKeyword + 1];
19361946
if (compressionFlag is not (0 or 1))
19371947
{
@@ -1956,6 +1966,11 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
19561966

19571967
int translatedKeywordStartIdx = langStartIdx + languageLength + 1;
19581968
int translatedKeywordLength = data[translatedKeywordStartIdx..].IndexOf((byte)0);
1969+
if (translatedKeywordLength < 0)
1970+
{
1971+
return;
1972+
}
1973+
19591974
string translatedKeyword = PngConstants.TranslatedEncoding.GetString(data.Slice(translatedKeywordStartIdx, translatedKeywordLength));
19601975

19611976
ReadOnlySpan<byte> keywordBytes = data[..zeroIndexKeyword];

tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,75 @@ public void Decode_TruncatedPhysChunk_ExceptionIsThrown()
9292
Assert.Equal("pHYs chunk is too short", exception.Message);
9393
}
9494

95+
// https://github.com/SixLabors/ImageSharp/issues/3079
96+
[Fact]
97+
public void Decode_CompressedTxtChunk_WithTruncatedData_DoesNotThrow()
98+
{
99+
byte[] payload = [137, 80, 78, 71, 13, 10, 26, 10, // PNG signature
100+
0, 0, 0, 13, // chunk length 13 bytes
101+
73, 72, 68, 82, // chunk type IHDR
102+
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, // data
103+
55, 110, 249, 36, // checksum
104+
0, 0, 0, 2, // chunk length
105+
122, 84, 88, 116, // chunk type zTXt
106+
1, 0, // truncated data
107+
100, 138, 166, 20, // crc
108+
0, 0, 0, 10, // chunk length 10 bytes
109+
73, 68, 65, 84, // chunk type IDAT
110+
120, 1, 99, 96, 0, 0, 0, 2, 0, 1, // data
111+
115, 117, 1, 24, // checksum
112+
0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; // end chunk
113+
114+
using MemoryStream stream = new(payload);
115+
using Image<Rgba32> image = Image.Load<Rgba32>(stream);
116+
}
117+
118+
// https://github.com/SixLabors/ImageSharp/issues/3079
119+
[Fact]
120+
public void Decode_InternationalText_WithTruncatedData_DoesNotThrow()
121+
{
122+
byte[] payload = [137, 80, 78, 71, 13, 10, 26, 10, // PNG signature
123+
0, 0, 0, 13, // chunk length 13 bytes
124+
73, 72, 68, 82, // chunk type IHDR
125+
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, // data
126+
55, 110, 249, 36, // checksum
127+
0, 0, 0, 2, // chunk length
128+
105, 84, 88, 116, // chunk type iTXt
129+
1, 0, // truncated data
130+
225, 200, 214, 33, // crc
131+
0, 0, 0, 10, // chunk length 10 bytes
132+
73, 68, 65, 84, // chunk type IDAT
133+
120, 1, 99, 96, 0, 0, 0, 2, 0, 1, // data
134+
115, 117, 1, 24, // checksum
135+
0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; // end chunk
136+
137+
using MemoryStream stream = new(payload);
138+
using Image<Rgba32> image = Image.Load<Rgba32>(stream);
139+
}
140+
141+
// https://github.com/SixLabors/ImageSharp/issues/3079
142+
[Fact]
143+
public void Decode_InternationalText_WithTruncatedDataAfterLanguageTag_DoesNotThrow()
144+
{
145+
byte[] payload = [137, 80, 78, 71, 13, 10, 26, 10, // PNG signature
146+
0, 0, 0, 13, // chunk length 13 bytes
147+
73, 72, 68, 82, // chunk type IHDR
148+
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, // data
149+
55, 110, 249, 36, // checksum
150+
0, 0, 0, 21, // chunk length
151+
105, 84, 88, 116, // chunk type iTXt
152+
73, 110, 116, 101, 114, 110, 97, 116, 105, 111, 110, 97, 108, 50, 0, 0, 0, 114, 117, 115, 0, // truncated data after language tag
153+
225, 200, 214, 33, // crc
154+
0, 0, 0, 10, // chunk length 10 bytes
155+
73, 68, 65, 84, // chunk type IDAT
156+
120, 1, 99, 96, 0, 0, 0, 2, 0, 1, // data
157+
115, 117, 1, 24, // checksum
158+
0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; // end chunk
159+
160+
using MemoryStream stream = new(payload);
161+
using Image<Rgba32> image = Image.Load<Rgba32>(stream);
162+
}
163+
95164
private static string GetChunkTypeName(uint value)
96165
{
97166
byte[] data = new byte[4];

0 commit comments

Comments
 (0)