@@ -120,6 +120,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
120
120
/// </summary>
121
121
private readonly PngCrcChunkHandling pngCrcChunkHandling ;
122
122
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
+
123
128
/// <summary>
124
129
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
125
130
/// </summary>
@@ -132,6 +137,7 @@ public PngDecoderCore(PngDecoderOptions options)
132
137
this . skipMetadata = options . GeneralOptions . SkipMetadata ;
133
138
this . memoryAllocator = this . configuration . MemoryAllocator ;
134
139
this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
140
+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
135
141
}
136
142
137
143
internal PngDecoderCore ( PngDecoderOptions options , bool colorMetadataOnly )
@@ -143,6 +149,7 @@ internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly)
143
149
this . configuration = options . GeneralOptions . Configuration ;
144
150
this . memoryAllocator = this . configuration . MemoryAllocator ;
145
151
this . pngCrcChunkHandling = options . PngCrcChunkHandling ;
152
+ this . maxUncompressedLength = options . MaxUncompressedAncillaryChunkSizeBytes ;
146
153
}
147
154
148
155
/// <inheritdoc/>
@@ -596,23 +603,7 @@ private static void ReadGammaChunk(PngMetadata pngMetadata, ReadOnlySpan<byte> d
596
603
private void InitializeImage < TPixel > ( ImageMetadata metadata , FrameControl frameControl , out Image < TPixel > image )
597
604
where TPixel : unmanaged, IPixel < TPixel >
598
605
{
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 ) ;
616
607
617
608
PngFrameMetadata frameMetadata = image . Frames . RootFrame . Metadata . GetPngMetadata ( ) ;
618
609
frameMetadata . FromChunk ( in frameControl ) ;
@@ -1572,7 +1563,7 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
1572
1563
1573
1564
ReadOnlySpan < byte > compressedData = data [ ( zeroIndex + 2 ) ..] ;
1574
1565
1575
- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] iccpProfileBytes ) )
1566
+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] iccpProfileBytes ) )
1576
1567
{
1577
1568
metadata . IccProfile = new IccProfile ( iccpProfileBytes ) ;
1578
1569
}
@@ -1582,9 +1573,10 @@ private void ReadColorProfileChunk(ImageMetadata metadata, ReadOnlySpan<byte> da
1582
1573
/// Tries to decompress zlib compressed data.
1583
1574
/// </summary>
1584
1575
/// <param name="compressedData">The compressed data.</param>
1576
+ /// <param name="maxLength">The maximum uncompressed length.</param>
1585
1577
/// <param name="uncompressedBytesArray">The uncompressed bytes array.</param>
1586
1578
/// <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 )
1588
1580
{
1589
1581
fixed ( byte * compressedDataBase = compressedData )
1590
1582
{
@@ -1604,6 +1596,12 @@ private unsafe bool TryDecompressZlibData(ReadOnlySpan<byte> compressedData, out
1604
1596
int bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
1605
1597
while ( bytesRead != 0 )
1606
1598
{
1599
+ if ( memoryStreamOutput . Length > maxLength )
1600
+ {
1601
+ uncompressedBytesArray = Array . Empty < byte > ( ) ;
1602
+ return false ;
1603
+ }
1604
+
1607
1605
memoryStreamOutput . Write ( destUncompressedData [ ..bytesRead ] ) ;
1608
1606
bytesRead = inflateStream . CompressedStream . Read ( destUncompressedData , 0 , destUncompressedData . Length ) ;
1609
1607
}
@@ -1746,7 +1744,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan<byt
1746
1744
/// <returns>The <see cref="bool"/>.</returns>
1747
1745
private bool TryDecompressTextData ( ReadOnlySpan < byte > compressedData , Encoding encoding , [ NotNullWhen ( true ) ] out string ? value )
1748
1746
{
1749
- if ( this . TryDecompressZlibData ( compressedData , out byte [ ] uncompressedData ) )
1747
+ if ( this . TryDecompressZlibData ( compressedData , this . maxUncompressedLength , out byte [ ] uncompressedData ) )
1750
1748
{
1751
1749
value = encoding . GetString ( uncompressedData ) ;
1752
1750
return true ;
0 commit comments