@@ -126,6 +126,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
126
126
/// </summary>
127
127
private readonly Crc32 crc32 = new ( ) ;
128
128
129
+ /// <summary>
130
+ /// The maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed.
131
+ /// </summary>
132
+ private readonly int maxUncompressedLength ;
133
+
129
134
/// <summary>
130
135
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
131
136
/// </summary>
@@ -138,6 +143,7 @@ public PngDecoderCore(PngDecoderOptions options)
138
143
this . skipMetadata = options . GeneralOptions . SkipMetadata ;
139
144
this . memoryAllocator = this . configuration . MemoryAllocator ;
140
145
this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
146
+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
141
147
}
142
148
143
149
internal PngDecoderCore ( PngDecoderOptions options , bool colorMetadataOnly )
@@ -149,6 +155,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
149
155
this . configuration = options . GeneralOptions . Configuration ;
150
156
this . memoryAllocator = this . configuration . MemoryAllocator ;
151
157
this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
158
+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
152
159
}
153
160
154
161
/// <inheritdoc/>
@@ -602,23 +609,7 @@ private static void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> d
602
609
private void InitializeImage < TPixel > ( ImageMetadata metadata , FrameControl frameControl , out Image < TPixel > image )
603
610
where TPixel : unmanaged, IPixel < TPixel >
604
611
{
605
- // When ignoring data CRCs, we can't use the image constructor that leaves the buffer uncleared.
606
- if ( this . pngCrcChunkHandling is PngCrcChunkHandling . IgnoreData or PngCrcChunkHandling . IgnoreAll )
607
- {
608
- image = new Image < TPixel > (
609
- this . configuration ,
610
- this . header . Width ,
611
- this . header . Height ,
612
- metadata ) ;
613
- }
614
- else
615
- {
616
- image = Image . CreateUninitialized < TPixel > (
617
- this . configuration ,
618
- this . header . Width ,
619
- this . header . Height ,
620
- metadata ) ;
621
- }
612
+ image = new Image < TPixel > ( this . configuration , this . header . Width , this . header . Height , metadata ) ;
622
613
623
614
PngFrameMetadata frameMetadata = image . Frames . RootFrame . Metadata . GetPngMetadata ( ) ;
624
615
frameMetadata . FromChunk ( in frameControl ) ;
@@ -1575,7 +1566,7 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
1575
1566
1576
1567
ReadOnlySpan < byte > compressedData = data [ ( zeroIndex + 2 ) ..] ;
1577
1568
1578
- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] iccpProfileBytes ) )
1569
+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] iccpProfileBytes ) )
1579
1570
{
1580
1571
metadata . IccProfile = new IccProfile ( iccpProfileBytes ) ;
1581
1572
}
@@ -1585,9 +1576,10 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
1585
1576
/// Tries to decompress zlib compressed data.
1586
1577
/// </summary>
1587
1578
/// <param name="compressedData">The compressed data.</param>
1579
+ /// <param name="maxLength">The maximum uncompressed length.</param>
1588
1580
/// <param name="uncompressedBytesArray">The uncompressed bytes array.</param>
1589
1581
/// <returns>True, if de-compressing was successful.</returns>
1590
- private unsafe bool TryDecompressZlibData ( ReadOnlySpan < byte > compressedData , out byte [ ] uncompressedBytesArray )
1582
+ private unsafe bool TryDecompressZlibData ( ReadOnlySpan < byte > compressedData , int maxLength , out byte [ ] uncompressedBytesArray )
1591
1583
{
1592
1584
fixed ( byte * compressedDataBase = compressedData )
1593
1585
{
@@ -1607,6 +1599,12 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan<byte> compressedData, out
1607
1599
int bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
1608
1600
while ( bytesRead != 0 )
1609
1601
{
1602
+ if ( memoryStreamOutput . Length > maxLength )
1603
+ {
1604
+ uncompressedBytesArray = Array . Empty < byte > ( ) ;
1605
+ return false ;
1606
+ }
1607
+
1610
1608
memoryStreamOutput . Write ( destUncompressedData [ ..bytesRead ] ) ;
1611
1609
bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
1612
1610
}
@@ -1749,7 +1747,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
1749
1747
/// <returns>The <see cref="bool"/>.</returns>
1750
1748
private bool TryDecompressTextData ( ReadOnlySpan < byte > compressedData , Encoding encoding , [ NotNullWhen ( true ) ] out string ? value )
1751
1749
{
1752
- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] uncompressedData ) )
1750
+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] uncompressedData ) )
1753
1751
{
1754
1752
value = encoding . GetString ( uncompressedData ) ;
1755
1753
return true ;
0 commit comments