@@ -125,6 +125,10 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
125125 /// A reusable Crc32 hashing instance.
126126 /// </summary>
127127 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 ;
128132
129133 /// <summary>
130134 /// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
@@ -138,6 +142,7 @@ public PngDecoderCore(PngDecoderOptions options)
138142 this . skipMetadata = options . GeneralOptions . SkipMetadata ;
139143 this . memoryAllocator = this . configuration . MemoryAllocator ;
140144 this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
145+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
141146 }
142147
143148 internal PngDecoderCore ( PngDecoderOptions options , bool colorMetadataOnly )
@@ -149,6 +154,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
149154 this . configuration = options . GeneralOptions . Configuration ;
150155 this . memoryAllocator = this . configuration . MemoryAllocator ;
151156 this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
157+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
152158 }
153159
154160 /// <inheritdoc/>
@@ -602,23 +608,7 @@ private static void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> d
602608 private void InitializeImage < TPixel > ( ImageMetadata metadata , FrameControl frameControl , out Image < TPixel > image )
603609 where TPixel : unmanaged, IPixel < TPixel >
604610 {
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 ) ;
622612
623613 PngFrameMetadata frameMetadata = image . Frames . RootFrame . Metadata . GetPngMetadata ( ) ;
624614 frameMetadata . FromChunk ( in frameControl ) ;
@@ -1575,7 +1565,7 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
15751565
15761566 ReadOnlySpan < byte > compressedData = data [ ( zeroIndex + 2 ) ..] ;
15771567
1578- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] iccpProfileBytes ) )
1568+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] iccpProfileBytes ) )
15791569 {
15801570 metadata . IccProfile = new IccProfile ( iccpProfileBytes ) ;
15811571 }
@@ -1585,9 +1575,10 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
15851575 /// Tries to decompress zlib compressed data.
15861576 /// </summary>
15871577 /// <param name="compressedData">The compressed data.</param>
1578+ /// <param name="maxLength">The maximum uncompressed length.</param>
15881579 /// <param name="uncompressedBytesArray">The uncompressed bytes array.</param>
15891580 /// <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 )
15911582 {
15921583 fixed ( byte * compressedDataBase = compressedData )
15931584 {
@@ -1607,6 +1598,12 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan<byte> compressedData, out
16071598 int bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
16081599 while ( bytesRead != 0 )
16091600 {
1601+ if ( memoryStreamOutput . Length > maxLength )
1602+ {
1603+ uncompressedBytesArray = Array . Empty < byte > ( ) ;
1604+ return false ;
1605+ }
1606+
16101607 memoryStreamOutput . Write ( destUncompressedData [ ..bytesRead ] ) ;
16111608 bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
16121609 }
@@ -1749,7 +1746,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
17491746 /// <returns>The <see cref="bool"/>.</returns>
17501747 private bool TryDecompressTextData ( ReadOnlySpan < byte > compressedData , Encoding encoding , [ NotNullWhen ( true ) ] out string ? value )
17511748 {
1752- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] uncompressedData ) )
1749+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] uncompressedData ) )
17531750 {
17541751 value = encoding . GetString ( uncompressedData ) ;
17551752 return true ;
0 commit comments