Skip to content

tarfile.StreamError: seeking backwards is not allowed due to unskipped block with bad checksum #130577

Closed

Description

@philgzl

Bug report

Bug description:

I am reading tar blocks from a stream. The stream can be resumed from an arbitrary position, therefore I am using tarfile.open with ignore_zeros=True. This works most of the time, but sometimes resuming causes a tarfile.StreamError: seeking backwards is not allowed. After inspection, it seems that this is caused by blocks passing the checksum test even though they are invalid. This causes wrong metadata to be parsed, which in turn causes the stream to crash.

Below is a minimal working example with a problematic block. This is a real block in my stream which is yielded from an archive created with tarfile. The archive is not corrupted, and when streaming from the beginning of the archive, everything works fine.

import io
import tarfile

buf = b'\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xfe\xff\xff\xff\x00\x00\x01\x00\x01\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xfe\xff\xff\xff\xff\xff\xfe\xff\xfe\xff\xff\xff\xff\xff\x01\x00\x01\x00\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xfe\xff\xfd\xff\xfe\xff\xff\xff\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xfe\xff\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x01\x00\x00\x00\x01\x00\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xff\xff\xfe\xff\xff\xff\x00\x00\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\xff\xfe\xff\xff\xff\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\xff\xfe\xff\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xfe\xff\xff\xff\x01\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\xfe\xff\xfe\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xfe\xff\xff\xff\x00\x00\xff\xff\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00'
f = io.BytesIO(buf)

with tarfile.open(mode="r|", fileobj=f, ignore_zeros=True) as tar:
    for member in tar:
        pass  # tarfile.StreamError: seeking backwards is not allowed

The backward seeking is caused by bad metadata parsing when calling tarfile.TarInfo.frombuf internally on the block.

import tarfile

buf = b'\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xfe\xff\xff\xff\x00\x00\x01\x00\x01\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xfe\xff\xff\xff\xff\xff\xfe\xff\xfe\xff\xff\xff\xff\xff\x01\x00\x01\x00\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xfe\xff\xfd\xff\xfe\xff\xff\xff\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\xfe\xff\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x01\x00\x00\x00\x01\x00\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xff\xff\xfe\xff\xff\xff\x00\x00\x01\x00\x00\x00\xff\xff\xff\xff\x00\x00\xfe\xff\xfe\xff\xff\xff\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\xff\xfe\xff\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xfe\xff\xff\xff\x01\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\xfe\xff\xfe\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\xfe\xff\xff\xff\xfe\xff\xff\xff\x00\x00\xff\xff\x00\x00\x01\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00'
info = tarfile.TarInfo.frombuf(buf, encoding="utf-8", errors="surrogateescape")
print(info.size)  # -4722366482873940180736

Tested with Python 3.12.8 and 3.13.2.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Feb 26, 2025
  2. aeurielesn commented on Jul 22, 2025

    @aeurielesn
    Contributor

    After having a look at the GNU tar code, I can see offsets must be non-negative numbers. I will put together a PR for this one.

  3. added a commit that references this issue on Jul 22, 2025
  4. aeurielesn commented on Jul 22, 2025

    @aeurielesn
    Contributor

    PR is up for review.

  5. added a commit that references this issue on Jul 28, 2025
  6. added 4 commits that reference this issue on Jul 28, 2025
  7. 27 remaining items

  8. frenzymadness commented on Sep 12, 2025

    @frenzymadness
    Contributor

    Am I correct when I think that versions of Python before this commit: ac3d137 are not vulnerable because the nti function did not support negative numbers, and therefore a header cannot contain a negative number leaving to a negative seek call?

  9. added a commit that references this issue on Sep 13, 2025
  10. hugovk commented on Sep 15, 2025

    @hugovk
    Member

    release-blocker triage: I see lots of merged backports, is this fixed or is there more to do?

  11. encukou commented on Sep 15, 2025

    @encukou
    Member

    @frenzymadness: That would be Python 2.6 and below, right? Don't think I can give an "official" security-related answer quickly. Catch me next week if you want explore this together.

    @hugovk: Looks like we're good!

  12. frenzymadness commented on Sep 15, 2025

    @frenzymadness
    Contributor

    @frenzymadness: That would be Python 2.6 and below, right? Don't think I can give an "official" security-related answer quickly. Catch me next week if you want explore this together.

    The commit is tagged in a way that suggests that it's included in 2.7, but it was removed in one weird merge after, so this applies basically to versions below 3.2.

    Let's discuss this later.

  13. added a commit that references this issue on May 14, 2026
  14. added 2 commits that reference this issue on Sep 18, 2026
  15. added 2 commits that reference this issue on Oct 1, 2026
  16. added a commit that references this issue on Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.10 (EOL)end of life3.11only security fixes3.12only security fixes3.13only security fixes3.14bugs and security fixes3.15bugs and security fixes3.9 (EOL)end of liferelease-blockerstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errortype-securityA security issue

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions