8000 [release/2.1] Tiff decoding robustness improvements (#2550) (#2554) · SixLabors/ImageSharp@749b1c0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 749b1c0

Browse files
authored
[release/2.1] Tiff decoding robustness improvements (#2550) (#2554)
* Tiff decoding robustness improvements (#2550) * tiled Tiff is not supported in 2.1, delete TiffDecoder_CanDecode_TiledWithBadZlib * also delete the files * and the constant
1 parent 3064b78 commit 749b1c0

File tree

5 files changed

+49
-28
lines changed

5 files changed

+49
-28
lines changed

src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -161,29 +161,25 @@ public override int Read(byte[] buffer, int offset, int count)
161161
bytesToRead = Math.Min(count - totalBytesRead, this.currentDataRemaining);
162162
this.currentDataRemaining -= bytesToRead;
163163
bytesRead = this.innerStream.Read(buffer, offset, bytesToRead);
164+
if (bytesRead == 0)
165+
{
166+
return totalBytesRead;
167+
}
168+
164169
totalBytesRead += bytesRead;
165170
}
166171

167172
return totalBytesRead;
168173
}
169174

170175
/// <inheritdoc/>
171-
public override long Seek(long offset, SeekOrigin origin)
172-
{
173-
throw new NotSupportedException();
174-
}
176+
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
175177

176178
/// <inheritdoc/>
177-
public override void SetLength(long value)
178-
{
179-
throw new NotSupportedException();
180-
}
179+
public override void SetLength(long value) => throw new NotSupportedException();
181180

182181
/// <inheritdoc/>
183-
public override void Write(byte[] buffer, int offset, int count)
184-
{
185-
throw new NotSupportedException();
186-
}
182+
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
187183

188184
/// <inheritdoc/>
189185
protected override void Dispose(bool disposing)
@@ -245,22 +241,17 @@ private bool InitializeInflateStream(bool isCriticalChunk)
245241
// CINFO is not defined in this specification for CM not equal to 8.
246242
throw new ImageFormatException($"Invalid window size for ZLIB header: cinfo={cinfo}");
247243
}
248-
else
249-
{
250-
return false;
251-
}
244+
245+
return false;
252246
}
253247
}
248+
else if (isCriticalChunk)
249+
{
250+
throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
251+
}
254252
else
255253
{
256-
if (isCriticalChunk)
257-
{
258-
throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
259-
}
260-
else
261-
{
262-
return false;
263-
}
254+
return false;
264255
}
265256

266257
// The preset dictionary.
@@ -269,7 +260,11 @@ private bool InitializeInflateStream(bool isCriticalChunk)
269260
{
270261
// We don't need this for inflate so simply skip by the next four bytes.
271262
// https://tools.ietf.org/html/rfc1950#page-6
272-
this.innerStream.Read(ChecksumBuffer, 0, 4);
263+
if (this.innerStream.Read(ChecksumBuffer, 0, 4) != 4)
264+
{
265+
return false;
266+
}
267+
273268
this.currentDataRemaining -= 4;
274269
}
275270

src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public DirectoryReader(Stream stream, MemoryAllocator allocator)
4343
public IEnumerable<ExifProfile> Read()
4444
{
4545
this.ByteOrder = ReadByteOrder(this.stream);
46-
var headerReader = new HeaderReader(this.stream, this.ByteOrder);
46+
HeaderReader headerReader = new(this.stream, this.ByteOrder);
4747
headerReader.ReadFileHeader();
4848

4949
this.nextIfdOffset = headerReader.FirstIfdOffset;
@@ -55,7 +55,12 @@ public IEnumerable<ExifProfile> Read()
5555
private static ByteOrder ReadByteOrder(Stream stream)
5656
{
5757
Span<byte> headerBytes = stackalloc byte[2];
58-
stream.Read(headerBytes);
58+
59+
if (stream.Read(headerBytes) != 2)
60+
{
61+
throw TiffThrowHelper.ThrowInvalidHeader();
62+
}
63+
5964
if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian)
6065
{
6166
return ByteOrder.LittleEndian;
@@ -74,7 +79,7 @@ private IEnumerable<ExifProfile> ReadIfds(bool isBigTiff)
7479
var readers = new List<EntryReader>();
7580
while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length)
7681
{
77-
var reader = new EntryReader(this.stream, this.ByteOrder, this.allocator);
82+
EntryReader reader = new(this.stream, this.ByteOrder, this.allocator);
7883
reader.ReadTags(isBigTiff, this.nextIfdOffset);
7984

8085
if (reader.BigValues.Count > 0)
@@ -88,6 +93,11 @@ private IEnumerable<ExifProfile> ReadIfds(bool isBigTiff)
8893
}
8994
}
9095

96+
if (this.nextIfdOffset >= reader.NextIfdOffset && reader.NextIfdOffset != 0)
97+
{
98+
TiffThrowHelper.ThrowImageFormatException("TIFF image contains circular directory offsets");
99+
}
100+
91101
this.nextIfdOffset = reader.NextIfdOffset;
92102
readers.Add(reader);
93103

tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,18 @@ public void TiffDecoder_ThrowsException_WithTooManyDirectories<TPixel>(TestImage
668668
}
669669
});
670670

671+
[Theory]
672+
[WithFile(JpegCompressedGray0000539558, PixelTypes.Rgba32)]
673+
public void TiffDecoder_ThrowsException_WithCircular_IFD_Offsets<TPixel>(TestImageProvider<TPixel> provider)
674+
where TPixel : unmanaged, IPixel<TPixel>
675+
=> Assert.Throws<ImageFormatException>(
676+
() =>
677+
{
678+
using (provider.GetImage(TiffDecoder))
679+
{
680+
}
681+
});
682+
671683
[Theory]
672684
[WithFileCollection(nameof(MultiframeTestImages), PixelTypes.Rgba32)]
673685
public void DecodeMultiframe<TPixel>(TestImageProvider<TPixel> provider)

tests/ImageSharp.Tests/TestImages.cs

Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ public static class Tiff
916916
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
917917
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";
918918
public const string Issues2123 = "Tiff/Issues/Issue2123.tiff";
919+
public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff";
919920

920921
public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff";
921922
public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:1f1ca630b5e46c7b5f21100fa8c0fbf27b79ca9da8cd95897667b64aedccf6e5
3+
size 539558