Repository navigation
Skip data of entries refused by $MAX_FILE_SIZE (fixes #47) - #53
Open
almightyfoon wants to merge 1 commit into
Open
almightyfoon wants to merge 1 commit into
almightyfoon wants to merge 1 commit into
Conversation
When an entry's declared size exceeds $Archive::Tar::MAX_FILE_SIZE, _read_tar() reported the error and did `next LOOP` without consuming the entry's data. Every following 512-byte data block was then parsed as a header and rejected with its own error, so a header declaring 2 GiB cost ~4M loop iterations and _error() calls (each building a Carp::longmess), largely defeating the CVE-2026-9538 mitigation. Read past the refused entry's data 64 blocks at a time, as the existing $skip path does, then continue with the next header. This never allocates more than 32 KiB, works on non-seekable handles (IO::Zlib, IO::Uncompress::*), and stops at EOF when the declared size runs past the end of the archive. Fixes GH jib#47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The CVE-2026-9538 fix (f9af014, released in 3.10) refuses entries whose declared
size exceeds
$Archive::Tar::MAX_FILE_SIZE. However, after reporting the error itdoes
next LOOPwithout consuming the entry's data._read_tar()then parses everyfollowing 512-byte data block as a header. Each block fails one of the existing
guards (null-padding check, checksum) and raises its own
_error(), and each ofthose builds a
Carp::longmess.The work therefore scales with the attacker-controlled size field, with one error
per block. A header declaring 2 GiB costs about 4M loop iterations and errors before
the next real header is reached, which largely defeats the mitigation. The Debian
perl maintainer has held back the bookworm/trixie backport of CVE-2026-9538 for this
reason (Debian #1138861, 2026-08-29).
Fix
Before
next LOOP, read past the refused entry's data 64 blocks (32 KiB) at a time.This is the same chunked-read pattern the existing
$skipbranch uses for filteredentries. As a result:
last LOOP)instead of re-scanning.
The remaining cost is proportional to the bytes actually present in the input, not
to the declared size.
Test
t/04_resolved_issues.tgains a "GH #47" block. WithMAX_FILE_SIZE = 1024, it checksthat an archive holding a 64 KiB entry followed by a small entry gives:
readanditerreturn only the small entry;exactly one warning.
Without the lib change, 4 of these assertions fail (129 warnings instead of 1). With
it, the full suite passes on perl 5.40.2.
For scale, here is a crafted 2 GiB-declared header followed by 32 MiB of real body:
gzip, bzip2 and xz archives behave the same way.
References