Skip to content

geotiff: parse_all_ifds silently truncates on IFD chain cycle #1913

@brendancol

Description

@brendancol

Summary

parse_all_ifds in xrspatial/geotiff/_header.py silently returns a truncated IFD list when the IFD chain in a TIFF file forms a cycle. The function already raises ValueError for two other malformed-chain conditions:

  • offset past EOF (_header.py:833)
  • chain exceeds MAX_IFDS (_header.py:844)

A cyclic chain is just as broken, but the current loop condition exits without complaint:

while offset != 0 and offset not in seen:   # _header.py:830
    seen.add(offset)
    ...

The caller gets back whatever was parsed before the cycle. That may look like a plausible first IFD while overview, mask, or metadata chains further down are corrupt.

Reproduction

import struct
from xrspatial.geotiff._header import parse_header, parse_all_ifds, TAG_IMAGE_WIDTH

out = bytearray()
out.extend(b'II'); out.extend(struct.pack('<H', 42)); out.extend(struct.pack('<I', 8))
# IFD A at offset 8 -> IFD B at offset 26
out.extend(struct.pack('<H', 1)); out.extend(struct.pack('<HHI', TAG_IMAGE_WIDTH, 4, 1))
out.extend(struct.pack('<I', 1)); out.extend(struct.pack('<I', 26))
# IFD B -> back to IFD A (cycle)
out.extend(struct.pack('<H', 1)); out.extend(struct.pack('<HHI', TAG_IMAGE_WIDTH, 4, 1))
out.extend(struct.pack('<I', 2)); out.extend(struct.pack('<I', 8))

data = bytes(out)
header = parse_header(data)
ifds = parse_all_ifds(data, header)
print(len(ifds))  # 2 -- no error raised

Fix

Restructure the loop so a repeat offset raises ValueError with the same file is malformed wording as the existing sibling errors:

while offset != 0:
    if offset in seen:
        raise ValueError(
            f"TIFF IFD chain has a cycle at offset {offset}; "
            f"file is malformed"
        )
    seen.add(offset)
    ...

Severity: low (defensive hardening / consistency).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions