A sub-IFD pointer field is a LONG/LONG8 array, and its element count comes from the file.
gamut_ifd::reader::resolve_pointers_with follows every element, parsing a directory per offset,
with no bound on how many. Depth is bounded (MAX_SUBIFD_DEPTH, 16) and cycles are refused, but
breadth is not — one entry can name as many children as its count field says, and a reader that
accepts N of them does N directory parses plus N membership tests.
Making the visited set a real set (filed separately) removes the quadratic term but not the linear
one: a 20 MB file that is nothing but a pointer array still costs 5M directory parses.
The question this issue is for is what the bound should be, and whether it belongs here at all:
- a fixed maximum children-per-entry (what value, and from which spec clause — TIFF 6.0 gives
none, DNG's SubIFDs usage is small, EXIF's Interop is one);
- a budget over the whole walk (total directories parsed) rather than per entry, which is what a
hostile tree actually spends;
- or leaving it to the consumer, since
gamut-tiff already carries a decode size cap and the
offsets must all be in bounds of a file the caller supplied.
Note the interaction with the existing loop guard: every offset must be distinct, so N is already
bounded by the number of distinct in-bounds offsets, i.e. by file length — which is why this is a
cost question rather than a memory-safety one.
Filed from the review of #520.
A sub-IFD pointer field is a
LONG/LONG8array, and its element count comes from the file.gamut_ifd::reader::resolve_pointers_withfollows every element, parsing a directory per offset,with no bound on how many. Depth is bounded (
MAX_SUBIFD_DEPTH, 16) and cycles are refused, butbreadth is not — one entry can name as many children as its count field says, and a reader that
accepts N of them does N directory parses plus N membership tests.
Making the visited set a real set (filed separately) removes the quadratic term but not the linear
one: a 20 MB file that is nothing but a pointer array still costs 5M directory parses.
The question this issue is for is what the bound should be, and whether it belongs here at all:
none, DNG's
SubIFDsusage is small, EXIF's Interop is one);hostile tree actually spends;
gamut-tiffalready carries a decode size cap and theoffsets must all be in bounds of a file the caller supplied.
Note the interaction with the existing loop guard: every offset must be distinct, so N is already
bounded by the number of distinct in-bounds offsets, i.e. by file length — which is why this is a
cost question rather than a memory-safety one.
Filed from the review of #520.