@@ -126,6 +126,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
126126 /// </summary>
127127 private readonly Crc32 crc32 = new ( ) ;
128128
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+
129134 /// <summary>
130135 /// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
131136 /// </summary>
@@ -138,6 +143,7 @@ public PngDecoderCore(PngDecoderOptions options)
138143 this . skipMetadata = options . GeneralOptions . SkipMetadata ;
139144 this . memoryAllocator = this . configuration . MemoryAllocator ;
140145 this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
146+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
141147 }
142148
143149 internal PngDecoderCore ( PngDecoderOptions options , bool colorMetadataOnly )
@@ -149,6 +155,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
149155 this . configuration = options . GeneralOptions . Configuration ;
150156 this . memoryAllocator = this . configuration . MemoryAllocator ;
151157 this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
158+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
152159 }
153160
154161 /// <inheritdoc/>
@@ -602,23 +609,7 @@ private static void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> d
602609 private void InitializeImage < TPixel > ( ImageMetadata metadata , FrameControl frameControl , out Image < TPixel > image )
603610 where TPixel : unmanaged, IPixel < TPixel >
604611 {
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 ) ;
622613
623614 PngFrameMetadata frameMetadata = image . Frames . RootFrame . Metadata . GetPngMetadata ( ) ;
624615 frameMetadata . FromChunk ( in frameControl ) ;
@@ -1575,7 +1566,7 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
15751566
15761567 ReadOnlySpan < byte > compressedData = data [ ( zeroIndex + 2 ) ..] ;
15771568
1578- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] iccpProfileBytes ) )
1569+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] iccpProfileBytes ) )
15791570 {
15801571 metadata . IccProfile = new IccProfile ( iccpProfileBytes ) ;
15811572 }
@@ -1585,9 +1576,10 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
15851576 /// Tries to decompress zlib compressed data.
15861577 /// </summary>
15871578 /// <param name="compressedData">The compressed data.</param>
1579+ /// <param name="maxLength">The maximum uncompressed length.</param>
15881580 /// <param name="uncompressedBytesArray">The uncompressed bytes array.</param>
15891581 /// <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 )
15911583 {
15921584 fixed ( byte * compressedDataBase = compressedData )
15931585 {
@@ -1607,6 +1599,12 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan<byte> compressedData, out
16071599 int bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
16081600 while ( bytesRead != 0 )
16091601 {
1602+ if ( memoryStreamOutput . Length > maxLength )
1603+ {
1604+ uncompressedBytesArray = Array . Empty < byte > ( ) ;
1605+ return false ;
1606+ }
1607+
16101608 memoryStreamOutput . Write ( destUncompressedData [ ..bytesRead ] ) ;
16111609 bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
16121610 }
@@ -1749,7 +1747,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
17491747 /// <returns>The <see cref="bool"/>.</returns>
17501748 private bool TryDecompressTextData ( ReadOnlySpan < byte > compressedData , Encoding encoding , [ NotNullWhen ( true ) ] out string ? value )
17511749 {
1752- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] uncompressedData ) )
1750+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] uncompressedData ) )
17531751 {
17541752 value = encoding . GetString ( uncompressedData ) ;
17551753 return true ;
0 commit comments