Skip to content

3.9.25.x: gh-151497 tarfile pre-allocation; pyexpatns.h renames - #121

Merged
icanhasmath merged 2 commits into
3.9.25.xfrom
3.9.25.x-review-followups
Oct 29, 2026
Merged

icanhasmath merged 2 commits into
3.9.25.xfrom
3.9.25.x-review-followups

Conversation

@icanhasmath

Copy link
Copy Markdown

Two follow-ups from the 3.7.17.8 review (#117) that also apply to this line. For the next 3.9.25.x release.

What's in it

  • tarfile: memory exhaustion via oversized extended-header (GNU long name / pax) size field python/cpython#151497: tarfile no longer pre-allocates the size an extended header claims. A GNU long name/link or pax header's size comes from the archive, and tarfile read it with one read(size), so a 512-byte file could make tarfile.open() allocate gigabytes before any extraction filter runs. The header is now read in 1 MiB chunks. Cherry-picked from upstream 3.13 (b83961a); upstream only backported it to 3.13 and 3.14. The test_tarfile conflict was context only.
  • pyexpatns.h renames the three Expat 2.9.0 functions it was missing. XML_SetHashSalt16Bytes, which pyexpat and _elementtree call, kept its unprefixed name, so it could clash with a system libexpat in the same process. XML_SetAllocTrackerActivationThreshold and XML_SetAllocTrackerMaximumAmplification are renamed too, as upstream and 3.10.22.x already do. Every XMLPARSEAPI function in the bundled expat.h is now renamed. Upstream main doesn't rename this one either.

Testing

  • tarfile: memory exhaustion via oversized extended-header (GNU long name / pax) size field python/cpython#151497: a 512-byte GNU long-name header that claims 3 GB, opened under a 1.5 GB address-space limit. Unfixed tarfile raises MemoryError trying to allocate the claimed size; with the fix it raises ReadError without the allocation. The three new ExtendedHeaderMemoryTest cases and the whole of test_tarfile pass.
  • pyexpatns.h: a Linux build of this branch has no unprefixed XML_ symbols in pyexpat, and PyExpat_XML_SetHashSalt16Bytes replaces XML_SetHashSalt16Bytes. test_pyexpat, test_xml_etree, test_xml_etree_c, test_sax, test_minidom, test_xml_dom_minicompat and test_tarfile pass.

miss-islington and others added 2 commits October 29, 2026 15:13
…file extended headers (pythonGH-151498) (pythonGH-151978)

tarfile reads a member's extended header (a GNU long name/link or a pax
header) with a single read sized by the header's size field:

    buf = tarfile.fileobj.read(self._block(self.size))

The size is taken from the archive and is not validated, so a ~512-byte
crafted file can claim several gigabytes (or, via base-256 encoding, far
more) and make read() pre-allocate that much memory -- on open/iterate,
before any extraction filter runs.

Read the extended-header data in bounded chunks instead, so an oversized
or truncated header can no longer force a huge allocation. The bytes
returned for valid archives are unchanged.
(cherry picked from commit da99711)

Co-authored-by: Shardul Deshpande <iamsharduld@users.noreply.github.com>

(cherry picked from commit b83961a)

3.9.25.x: the test_tarfile conflict was context only (test_extractfile_attrs, pythongh-74468, isn't on this line); only the ReadSizeRecorder and ExtendedHeaderMemoryTest classes are added.
pyexpatns.h prefixes the bundled Expat's exported symbols with PyExpat_ so
they cannot clash with a system libexpat loaded in the same process. Expat
2.9.0 added XML_SetAllocTrackerActivationThreshold and
XML_SetAllocTrackerMaximumAmplification (pythongh-90949, CVE-2025-59375) and
XML_SetHashSalt16Bytes, but the header did not rename them. The first two
match upstream, 3.10.22.x and 3.7.17.x; pyexpat and _elementtree call
XML_SetHashSalt16Bytes, which upstream does not rename yet either.
Same change as 3.7.17.x 69ab1c8 (#117 review).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@icanhasmath icanhasmath mentioned this pull request Oct 29, 2026
@manoelc-dev
manoelc-dev self-requested a review October 29, 2026 22:38

@ezequielp-activestate ezequielp-activestate left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving.

  • The pythongh-151497 port matches upstream 3.13 (b83961ade8) line for line, apart from one blank line. Upstream has no follow-ups to it.
  • With this branch's Lib/test on a python:3.9 image, test_tarfile passes with this branch's tarfile.py and fails with the 3.9.25.x one.
  • The pyexpatns.h change adds the two XML_SetAllocTracker* renames and XML_SetHashSalt16Bytes. Every XML_* function declared in the bundled expat.h now has a PyExpat_ rename.

@manoelc-dev
manoelc-dev removed their request for review October 29, 2026 22:43
@icanhasmath
icanhasmath merged commit 08bd961 into 3.9.25.x Oct 29, 2026
20 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.

3 participants