@@ -120,6 +120,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
120120 /// </summary>
121121 private readonly PngCrcChunkHandling pngCrcChunkHandling ;
122122
123+ /// <summary>
124+ /// The maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed.
125+ /// </summary>
126+ private readonly int maxUncompressedLength ;
127+
123128 /// <summary>
124129 /// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
125130 /// </summary>
@@ -132,6 +137,7 @@ public PngDecoderCore(PngDecoderOptions options)
132137 this . skipMetadata = options . GeneralOptions . SkipMetadata ;
133138 this . memoryAllocator = this . configuration . MemoryAllocator ;
134139 this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
140+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
135141 }
136142
137143 internal PngDecoderCore ( PngDecoderOptions options , bool colorMetadataOnly )
@@ -143,6 +149,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
143149 this . configuration = options . GeneralOptions . Configuration ;
144150 this . memoryAllocator = this . configuration . MemoryAllocator ;
145151 this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
152+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
146153 }
147154
148155 /// <inheritdoc/>
@@ -596,23 +603,7 @@ private static void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> d
596603 private void InitializeImage < TPixel > ( ImageMetadata metadata , FrameControl frameControl , out Image < TPixel > image )
597604 where TPixel : unmanaged, IPixel < TPixel >
598605 {
599- // When ignoring data CRCs, we can't use the image constructor that leaves the buffer uncleared.
600- if ( this . pngCrcChunkHandling is PngCrcChunkHandling . IgnoreData or PngCrcChunkHandling . IgnoreAll )
601- {
602- image = new Image < TPixel > (
603- this . configuration ,
604- this . header . Width ,
605- this . header . Height ,
606- metadata ) ;
607- }
608- else
609- {
610- image = Image . CreateUninitialized < TPixel > (
611- this . configuration ,
612- this . header . Width ,
613- this . header . Height ,
614- metadata ) ;
615- }
606+ image = new Image < TPixel > ( this . configuration , this . header . Width , this . header . Height , metadata ) ;
616607
617608 PngFrameMetadata frameMetadata = image . Frames . RootFrame . Metadata . GetPngMetadata ( ) ;
618609 frameMetadata . FromChunk ( in frameControl ) ;
@@ -1572,7 +1563,7 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
15721563
15731564 ReadOnlySpan < byte > compressedData = data [ ( zeroIndex + 2 ) ..] ;
15741565
1575- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] iccpProfileBytes ) )
1566+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] iccpProfileBytes ) )
15761567 {
15771568 metadata . IccProfile = new IccProfile ( iccpProfileBytes ) ;
15781569 }
@@ -1582,9 +1573,10 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
15821573 /// Tries to decompress zlib compressed data.
15831574 /// </summary>
15841575 /// <param name="compressedData">The compressed data.</param>
1576+ /// <param name="maxLength">The maximum uncompressed length.</param>
15851577 /// <param name="uncompressedBytesArray">The uncompressed bytes array.</param>
15861578 /// <returns>True, if de-compressing was successful.</returns>
1587- private unsafe bool TryDecompressZlibData ( ReadOnlySpan < byte > compressedData , out byte [ ] uncompressedBytesArray )
1579+ private unsafe bool TryDecompressZlibData ( ReadOnlySpan < byte > compressedData , int maxLength , out byte [ ] uncompressedBytesArray )
15881580 {
15891581 fixed ( byte * compressedDataBase = compressedData )
15901582 {
@@ -1604,6 +1596,12 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan<byte> compressedData, out
16041596 int bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
16051597 while ( bytesRead != 0 )
16061598 {
1599+ if ( memoryStreamOutput . Length > maxLength )
1600+ {
1601+ uncompressedBytesArray = Array . Empty < byte > ( ) ;
1602+ return false ;
1603+ }
1604+
16071605 memoryStreamOutput . Write ( destUncompressedData [ ..bytesRead ] ) ;
16081606 bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
16091607 }
@@ -1746,7 +1744,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
17461744 /// <returns>The <see cref="bool"/>.</returns>
17471745 private bool TryDecompressTextData ( ReadOnlySpan < byte > compressedData , Encoding encoding , [ NotNullWhen ( true ) ] out string ? value )
17481746 {
1749- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] uncompressedData ) )
1747+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] uncompressedData ) )
17501748 {
17511749 value = encoding . GetString ( uncompressedData ) ;
17521750 return true ;
0 commit comments