Skip to content

Commit

Permalink
Tiff decoding robustness improvements (#2550)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonfirsov committed Oct 15, 2023
1 parent 688e242 commit d675525
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 28 deletions.
45 changes: 20 additions & 25 deletions src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,29 +161,25 @@ public override int Read(byte[] buffer, int offset, int count)
bytesToRead = Math.Min(count - totalBytesRead, this.currentDataRemaining);
this.currentDataRemaining -= bytesToRead;
bytesRead = this.innerStream.Read(buffer, offset, bytesToRead);
if (bytesRead == 0)
{
return totalBytesRead;
}

totalBytesRead += bytesRead;
}

return totalBytesRead;
}

/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();

/// <inheritdoc/>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void SetLength(long value) => throw new NotSupportedException();

/// <inheritdoc/>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();

/// <inheritdoc/>
protected override void Dispose(bool disposing)
Expand Down Expand Up @@ -245,22 +241,17 @@ private bool InitializeInflateStream(bool isCriticalChunk)
// CINFO is not defined in this specification for CM not equal to 8.
throw new ImageFormatException($"Invalid window size for ZLIB header: cinfo={cinfo}");
}
else
{
return false;
}

return false;
}
}
else if (isCriticalChunk)
{
throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
}
else
{
if (isCriticalChunk)
{
throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
}
else
{
return false;
}
return false;
}

// The preset dictionary.
Expand All @@ -269,7 +260,11 @@ private bool InitializeInflateStream(bool isCriticalChunk)
{
// We don't need this for inflate so simply skip by the next four bytes.
// https://tools.ietf.org/html/rfc1950#page-6
this.innerStream.Read(ChecksumBuffer, 0, 4);
if (this.innerStream.Read(ChecksumBuffer, 0, 4) != 4)
{
return false;
}

this.currentDataRemaining -= 4;
}

Expand Down
16 changes: 13 additions & 3 deletions src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public DirectoryReader(Stream stream, MemoryAllocator allocator)
public IEnumerable<ExifProfile> Read()
{
this.ByteOrder = ReadByteOrder(this.stream);
var headerReader = new HeaderReader(this.stream, this.ByteOrder);
HeaderReader headerReader = new(this.stream, this.ByteOrder);
headerReader.ReadFileHeader();

this.nextIfdOffset = headerReader.FirstIfdOffset;
Expand All @@ -55,7 +55,12 @@ public IEnumerable<ExifProfile> Read()
private static ByteOrder ReadByteOrder(Stream stream)
{
Span<byte> headerBytes = stackalloc byte[2];
stream.Read(headerBytes);

if (stream.Read(headerBytes) != 2)
{
throw TiffThrowHelper.ThrowInvalidHeader();
}

if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian)
{
return ByteOrder.LittleEndian;
Expand All @@ -74,7 +79,7 @@ private IEnumerable<ExifProfile> ReadIfds(bool isBigTiff)
var readers = new List<EntryReader>();
while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length)
{
var reader = new EntryReader(this.stream, this.ByteOrder, this.allocator);
EntryReader reader = new(this.stream, this.ByteOrder, this.allocator);
reader.ReadTags(isBigTiff, this.nextIfdOffset);

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

if (this.nextIfdOffset >= reader.NextIfdOffset && reader.NextIfdOffset != 0)
{
TiffThrowHelper.ThrowImageFormatException("TIFF image contains circular directory offsets");
}

this.nextIfdOffset = reader.NextIfdOffset;
readers.Add(reader);

Expand Down
24 changes: 24 additions & 0 deletions tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,30 @@ public void TiffDecoder_ThrowsException_WithTooManyDirectories<TPixel>(TestImage
}
});

[Theory]
[WithFile(JpegCompressedGray0000539558, PixelTypes.Rgba32)]
public void TiffDecoder_ThrowsException_WithCircular_IFD_Offsets<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
=> Assert.Throws<ImageFormatException>(
() =>
{
using (provider.GetImage(TiffDecoder))
{
}
});

[Theory]
[WithFile(Tiled0000023664, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_TiledWithBadZlib<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(TiffDecoder);

// ImageMagick cannot decode this image.
image.DebugSave(provider);
image.CompareToReferenceOutput(ImageComparer.Exact, provider, appendPixelTypeToFileName: false);
}

[Theory]
[WithFileCollection(nameof(MultiframeTestImages), PixelTypes.Rgba32)]
public void DecodeMultiframe<TPixel>(TestImageProvider<TPixel> provider)
Expand Down
2 changes: 2 additions & 0 deletions tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,8 @@ public static class Tiff
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";
public const string Issues2123 = "Tiff/Issues/Issue2123.tiff";
public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff";
public const string Tiled0000023664 = "Tiff/Issues/tiled-0000023664.tiff";

public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff";
public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff";
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Git LFS file not shown
3 changes: 3 additions & 0 deletions tests/Images/Input/Tiff/Issues/tiled-0000023664.tiff
Git LFS file not shown

0 comments on commit d675525

Please sign in to comment.