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