[3.14] gh-90949: add Expat API to prevent XML deadly allocations (CVE-2025-59375) (GH-139234) (#139359)

* [3.14] gh-90949: add Expat API to prevent XML deadly allocations (CVE-2025-59375) (GH-139234)

Expose the XML Expat 2.7.2 mitigation APIs to disallow use of
disproportional amounts of dynamic memory from within an Expat
parser (see CVE-2025-59375 for instance).

The exposed APIs are available on Expat parsers, that is,
parsers created by `xml.parsers.expat.ParserCreate()`, as:

- `parser.SetAllocTrackerActivationThreshold(threshold)`, and
- `parser.SetAllocTrackerMaximumAmplification(max_factor)`.

(cherry picked from commit f04bea44c3)
(cherry picked from commit 68a1778b77)
This commit is contained in:
Bénédikt Tran 2025-11-02 10:33:36 +01:00 committed by GitHub
parent 4d7fab9b15
commit bf2865f80f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 586 additions and 32 deletions

View file

@ -72,6 +72,13 @@ The :mod:`xml.parsers.expat` module contains two functions:
*encoding* [1]_ is given it will override the implicit or explicit encoding of the
document.
.. _xmlparser-non-root:
Parsers created through :func:`!ParserCreate` are called "root" parsers,
in the sense that they do not have any parent parser attached. Non-root
parsers are created by :meth:`parser.ExternalEntityParserCreate
<xmlparser.ExternalEntityParserCreate>`.
Expat can optionally do XML namespace processing for you, enabled by providing a
value for *namespace_separator*. The value must be a one-character string; a
:exc:`ValueError` will be raised if the string has an illegal length (``None``
@ -231,6 +238,55 @@ XMLParser Objects
.. versionadded:: 3.13
:class:`!xmlparser` objects have the following methods to mitigate some
common XML vulnerabilities.
.. method:: xmlparser.SetAllocTrackerActivationThreshold(threshold, /)
Sets the number of allocated bytes of dynamic memory needed to activate
protection against disproportionate use of RAM.
By default, parser objects have an allocation activation threshold of 64 MiB,
or equivalently 67,108,864 bytes.
An :exc:`ExpatError` is raised if this method is called on a
|xml-non-root-parser| parser.
The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset`
should not be used as they may have no special meaning.
.. versionadded:: next
.. method:: xmlparser.SetAllocTrackerMaximumAmplification(max_factor, /)
Sets the maximum amplification factor between direct input and bytes
of dynamic memory allocated.
The amplification factor is calculated as ``allocated / direct``
while parsing, where ``direct`` is the number of bytes read from
the primary document in parsing and ``allocated`` is the number
of bytes of dynamic memory allocated in the parser hierarchy.
The *max_factor* value must be a non-NaN :class:`float` value greater than
or equal to 1.0. Amplification factors greater than 100.0 can be observed
near the start of parsing even with benign files in practice. In particular,
the activation threshold should be carefully chosen to avoid false positives.
By default, parser objects have a maximum amplification factor of 100.0.
An :exc:`ExpatError` is raised if this method is called on a
|xml-non-root-parser| parser or if *max_factor* is outside the valid range.
The corresponding :attr:`~ExpatError.lineno` and :attr:`~ExpatError.offset`
should not be used as they may have no special meaning.
.. note::
The maximum amplification factor is only considered if the threshold
that can be adjusted by :meth:`.SetAllocTrackerActivationThreshold`
is exceeded.
.. versionadded:: next
:class:`xmlparser` objects have the following attributes:
@ -954,3 +1010,4 @@ The ``errors`` module has the following attributes:
not. See https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDecl
and https://www.iana.org/assignments/character-sets/character-sets.xhtml.
.. |xml-non-root-parser| replace:: :ref:`non-root <xmlparser-non-root>`