Skip to content

Decode TIFF files with large strips and backwards directory chains - #3231

Merged
JimBobSquarePants merged 3 commits into
SixLabors:mainfrom
jafin:jf/tiff-decoder-malformed-input
Oct 27, 2026
Merged

JimBobSquarePants merged 3 commits into
SixLabors:mainfrom
jafin:jf/tiff-decoder-malformed-input

Conversation

@jafin

@jafin jafin commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Decode valid TIFF files whose strip sizes exceed the allocator's single-buffer limit or whose directories appear in reverse file order.

  • Apply the RowsPerStrip default to both chunky and planar images. Limit strip allocation to the image height. Reject zero RowsPerStrip in every integrity mode.
  • Read large uncompressed strips one row at a time through the existing decompressor and color decoders. Reuse the row buffers. Keep subsampled YCbCr on the complete-strip path.
  • Track visited directory offsets instead of rejecting decreasing offsets. Start with capacity for four offsets. Keep circular-chain detection and the directory-count limit for TIFF and BigTIFF.
  • Record root dimensions before frame allocation. Dispose a failed frame before the caller takes ownership, including failures during ICC conversion.

The review also corrected incomplete-data handling. Strict and IgnoreAncillary reject short uncompressed data. IgnoreImageData retains available samples and clears missing samples in reused buffers. Reads stay within StripByteCounts. YCbCr size calculations account for subsampling. Planar tile buffers use the depth of each plane.

Tests use stored inputs. There are no runtime TIFF builders or generated image inputs. Independent directory and strip parsing checked the fixture layouts and 16-bit sample bytes. Libtiff also decoded the valid RGB and reversed-directory inputs.

Verification: Release on .NET 10, 897 TIFF and general decoder regression tests passed. This includes 28 strip-layout cases covering all integrity modes. The original PR failed six of the added structural and incomplete-data cases before the review corrections. No existing tolerances or reference images changed.

Fixes #3243

A missing RowsPerStrip, or one above the image height, is now limited to the height, so planar files without
the entry decode and the strip buffer only holds rows that exist. Uncompressed strips, chunky or planar, that are
larger than the single buffer allocation limit are read one row at a time. The image dimensions are recorded
before the root frame is allocated, so an allocation failure reports the real size, and a frame that fails to
decode is released. Directory chains that go backwards in the file are accepted; only a revisited directory is
reported as circular.
@JimBobSquarePants
JimBobSquarePants merged commit d1cd2b5 into SixLabors:main Oct 27, 2026
16 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TIFF decoder rejects valid files: missing or large RowsPerStrip, strips above the buffer limit, backwards IFD chains, and "0x0" in allocation errors

2 participants