Browse Source

Merge pull request #3081 from SixLabors/bp/fixIssue3079

Add checks, if enough data is present when reading PNG text chunks
pull/3089/head
James Jackson-South 2 months ago
committed by GitHub
parent
commit
89face0b89
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 25
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 69
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs

25
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -1402,26 +1402,31 @@ internal sealed class PngDecoderCore : ImageDecoderCore
return;
}
int zeroIndex = data.IndexOf((byte)0);
if (zeroIndex is < PngConstants.MinTextKeywordLength or > PngConstants.MaxTextKeywordLength)
int keywordEnd = data.IndexOf((byte)0);
if (keywordEnd is < PngConstants.MinTextKeywordLength or > PngConstants.MaxTextKeywordLength)
{
return;
}
byte compressionMethod = data[zeroIndex + 1];
if (keywordEnd < 0 || keywordEnd + 2 > data.Length)
{
return; // Not enough data for keyword + null + compression method.
}
byte compressionMethod = data[keywordEnd + 1];
if (compressionMethod != 0)
{
// Only compression method 0 is supported (zlib datastream with deflate compression).
return;
}
ReadOnlySpan<byte> keywordBytes = data[..zeroIndex];
ReadOnlySpan<byte> keywordBytes = data[..keywordEnd];
if (!TryReadTextKeyword(keywordBytes, out string name))
{
return;
}
ReadOnlySpan<byte> compressedData = data[(zeroIndex + 2)..];
ReadOnlySpan<byte> compressedData = data[(keywordEnd + 2)..];
if (this.TryDecompressTextData(compressedData, PngConstants.Encoding, out string? uncompressed)
&& !TryReadTextChunkMetadata(baseMetadata, name, uncompressed))
@ -1932,6 +1937,11 @@ internal sealed class PngDecoderCore : ImageDecoderCore
return;
}
if (zeroIndexKeyword < 0 || zeroIndexKeyword + 4 > data.Length)
{
return; // Not enough data for keyword + null + flag + method + language.
}
byte compressionFlag = data[zeroIndexKeyword + 1];
if (compressionFlag is not (0 or 1))
{
@ -1956,6 +1966,11 @@ internal sealed class PngDecoderCore : ImageDecoderCore
int translatedKeywordStartIdx = langStartIdx + languageLength + 1;
int translatedKeywordLength = data[translatedKeywordStartIdx..].IndexOf((byte)0);
if (translatedKeywordLength < 0)
{
return;
}
string translatedKeyword = PngConstants.TranslatedEncoding.GetString(data.Slice(translatedKeywordStartIdx, translatedKeywordLength));
ReadOnlySpan<byte> keywordBytes = data[..zeroIndexKeyword];

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

@ -92,6 +92,75 @@ public partial class PngDecoderTests
Assert.Equal("pHYs chunk is too short", exception.Message);
}
// https://github.com/SixLabors/ImageSharp/issues/3079
[Fact]
public void Decode_CompressedTxtChunk_WithTruncatedData_DoesNotThrow()
{
byte[] payload = [137, 80, 78, 71, 13, 10, 26, 10, // PNG signature
0, 0, 0, 13, // chunk length 13 bytes
73, 72, 68, 82, // chunk type IHDR
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, // data
55, 110, 249, 36, // checksum
0, 0, 0, 2, // chunk length
122, 84, 88, 116, // chunk type zTXt
1, 0, // truncated data
100, 138, 166, 20, // crc
0, 0, 0, 10, // chunk length 10 bytes
73, 68, 65, 84, // chunk type IDAT
120, 1, 99, 96, 0, 0, 0, 2, 0, 1, // data
115, 117, 1, 24, // checksum
0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; // end chunk
using MemoryStream stream = new(payload);
using Image<Rgba32> image = Image.Load<Rgba32>(stream);
}
// https://github.com/SixLabors/ImageSharp/issues/3079
[Fact]
public void Decode_InternationalText_WithTruncatedData_DoesNotThrow()
{
byte[] payload = [137, 80, 78, 71, 13, 10, 26, 10, // PNG signature
0, 0, 0, 13, // chunk length 13 bytes
73, 72, 68, 82, // chunk type IHDR
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, // data
55, 110, 249, 36, // checksum
0, 0, 0, 2, // chunk length
105, 84, 88, 116, // chunk type iTXt
1, 0, // truncated data
225, 200, 214, 33, // crc
0, 0, 0, 10, // chunk length 10 bytes
73, 68, 65, 84, // chunk type IDAT
120, 1, 99, 96, 0, 0, 0, 2, 0, 1, // data
115, 117, 1, 24, // checksum
0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; // end chunk
using MemoryStream stream = new(payload);
using Image<Rgba32> image = Image.Load<Rgba32>(stream);
}
// https://github.com/SixLabors/ImageSharp/issues/3079
[Fact]
public void Decode_InternationalText_WithTruncatedDataAfterLanguageTag_DoesNotThrow()
{
byte[] payload = [137, 80, 78, 71, 13, 10, 26, 10, // PNG signature
0, 0, 0, 13, // chunk length 13 bytes
73, 72, 68, 82, // chunk type IHDR
0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, // data
55, 110, 249, 36, // checksum
0, 0, 0, 21, // chunk length
105, 84, 88, 116, // chunk type iTXt
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
225, 200, 214, 33, // crc
0, 0, 0, 10, // chunk length 10 bytes
73, 68, 65, 84, // chunk type IDAT
120, 1, 99, 96, 0, 0, 0, 2, 0, 1, // data
115, 117, 1, 24, // checksum
0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; // end chunk
using MemoryStream stream = new(payload);
using Image<Rgba32> image = Image.Load<Rgba32>(stream);
}
private static string GetChunkTypeName(uint value)
{
byte[] data = new byte[4];

Loading…
Cancel
Save