[3.7] gh-95778: CVE-2020-10735: Prevent DoS by very large int() (GH-9… · python/cpython@15ec1af · GitHub
Skip to content

Commit 15ec1af

Browse files
authored
[3.7] gh-95778: CVE-2020-10735: Prevent DoS by very large int() (GH-96504)
Converting between `int` and `str` in bases other than 2 (binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) now raises a `ValueError` if the number of digits in string form is above a limit to avoid potential denial of service attacks due to the algorithmic complexity. This is a mitigation for CVE-2020-10735 (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735). This new limit can be configured or disabled by environment variable, command line flag, or :mod:`sys` APIs. See the `Integer String Conversion Length Limitation` documentation. The default limit is 4300 digits in string form. Patch by Gregory P. Smith [Google] and Christian Heimes [Red Hat] with feedback from Victor Stinner, Thomas Wouters, Steve Dower, Ned Deily, and Mark Dickinson.
1 parent d5fe995 commit 15ec1af

26 files changed

Lines changed: 882 additions & 22 deletions

Doc/data/python3.7m.abi

Lines changed: 4 additions & 0 deletions

Doc/library/functions.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,14 @@ are always available. They are listed here in alphabetical order.
774774
.. versionchanged:: 3.7
775775
*x* is now a positional-only parameter.
776776

777+
.. versionchanged:: 3.7.14
778+
:class:`int` string inputs and string representations can be limited to
779+
help avoid denial of service attacks. A :exc:`ValueError` is raised when
780+
the limit is exceeded while converting a string *x* to an :class:`int` or
781+
when converting an :class:`int` into a string would exceed the limit.
782+
See the :ref:`integer string conversion length limitation
783+
<int_max_str_digits>` documentation.
784+
777785

778786
.. function:: isinstance(object, classinfo)
779787

Doc/library/json.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ is a lightweight data interchange format inspired by
1818
`JavaScript <https://en.wikipedia.org/wiki/JavaScript>`_ object literal syntax
1919
(although it is not a strict subset of JavaScript [#rfc-errata]_ ).
2020

21+
.. warning::
22+
Be cautious when parsing JSON data from untrusted sources. A malicious
23+
JSON string may cause the decoder to consume considerable CPU and memory
24+
resources. Limiting the size of data to be parsed is recommended.
25+
2126
:mod:`json` exposes an API familiar to users of the standard library
2227
:mod:`marshal` and :mod:`pickle` modules.
2328

@@ -243,6 +248,12 @@ Basic Usage
243248
be used to use another datatype or parser for JSON integers
244249
(e.g. :class:`float`).
245250

251+
.. versionchanged:: 3.7.14
252+
The default *parse_int* of :func:`int` now limits the maximum length of
253+
the integer string via the interpreter's :ref:`integer string
254+
conversion length limitation <int_max_str_digits>` to help avoid denial
255+
of service attacks.
256+
246257
*parse_constant*, if specified, will be called with one of the following
247258
strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.
248259
This can be used to raise an exception if invalid JSON numbers

Doc/library/stdtypes.rst

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,6 +4741,165 @@ types, where they are relevant. Some of these are not reported by the
47414741
[<class 'bool'>]
47424742

47434743

4744+
.. _int_max_str_digits:
4745+
4746+
Integer string conversion length limitation
4747+
===========================================
4748+
4749+
CPython has a global limit for converting between :class:`int` and :class:`str`
4750+
to mitigate denial of service attacks. This limit *only* applies to decimal or
4751+
other non-power-of-two number bases. Hexadecimal, octal, and binary conversions
4752+
are unlimited. The limit can be configured.
4753+
4754+
The :class:`int` type in CPython is an abitrary length number stored in binary
4755+
form (commonly known as a "bignum"). There exists no algorithm that can convert
4756+
a string to a binary integer or a binary integer to a string in linear time,
4757+
*unless* the base is a power of 2. Even the best known algorithms for base 10
4758+
have sub-quadratic complexity. Converting a large value such as ``int('1' *
4759+
500_000)`` can take over a second on a fast CPU.
4760+
4761+
Limiting conversion size offers a practical way to avoid `CVE-2020-10735
4762+
<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735>`_.
4763+
4764+
The limit is applied to the number of digit characters in the input or output
4765+
string when a non-linear conversion algorithm would be involved. Underscores
4766+
and the sign are not counted towards the limit.
4767+
4768+
When an operation would exceed the limit, a :exc:`ValueError` is raised:
4769+
4770+
.. doctest::
4771+
4772+
>>> import sys
4773+
>>> sys.set_int_max_str_digits(4300) # Illustrative, this is the default.
4774+
>>> _ = int('2' * 5432)
4775+
Traceback (most recent call last):
4776+
...
4777+
ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits.
4778+
>>> i = int('2' * 4300)
4779+
>>> len(str(i))
4780+
4300
4781+
>>> i_squared = i*i
4782+
>>> len(str(i_squared))
4783+
Traceback (most recent call last):
4784+
...
4785+
ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits.
4786+
>>> len(hex(i_squared))
4787+
7144
4788+
>>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited.
4789+
4790+
The default limit is 4300 digits as provided in
4791+
:data:`sys.int_info.default_max_str_digits <sys.int_info>`.
4792+
The lowest limit that can be configured is 640 digits as provided in
4793+
:data:`sys.int_info.str_digits_check_threshold <sys.int_info>`.
4794+
4795+
Verification:
4796+
4797+
.. doctest::
4798+
4799+
>>> import sys
4800+
>>> assert sys.int_info.default_max_str_digits == 4300, sys.int_info
4801+
>>> assert sys.int_info.str_digits_check_threshold == 640, sys.int_info
4802+
>>> msg = int('578966293710682886880994035146873798396722250538762761564'
4803+
... '9252925514383915483333812743580549779436104706260696366600'
4804+
... '571186405732').to_bytes(53, 'big')
4805+
...
4806+
4807+
.. versionadded:: 3.7.14
4808+
4809+
Affected APIs
4810+
-------------
4811+
4812+
The limitation only applies to potentially slow conversions between :class:`int`
4813+
and :class:`str` or :class:`bytes`:
4814+
4815+
* ``int(string)`` with default base 10.
4816+
* ``int(string, base)`` for all bases that are not a power of 2.
4817+
* ``str(integer)``.
4818+
* ``repr(integer)``
4819+
* any other string conversion to base 10, for example ``f"{integer}"``,
4820+
``"{}".format(integer)``, or ``b"%d" % integer``.
4821+
4822+
The limitations do not apply to functions with a linear algorithm:
4823+
4824+
* ``int(string, base)`` with base 2, 4, 8, 16, or 32.
4825+
* :func:`int.from_bytes` and :func:`int.to_bytes`.
4826+
* :func:`hex`, :func:`oct`, :func:`bin`.
4827+
* :ref:`formatspec` for hex, octal, and binary numbers.
4828+
* :class:`str` to :class:`float`.
4829+
* :class:`str` to :class:`decimal.Decimal`.
4830+
4831+
Configuring the limit
4832+
---------------------
4833+
4834+
Before Python starts up you can use an environment variable or an interpreter
4835+
command line flag to configure the limit:
4836+
4837+
* :envvar:`PYTHONINTMAXSTRDIGITS`, e.g.
4838+
``PYTHONINTMAXSTRDIGITS=640 python3`` to set the limit to 640 or
4839+
``PYTHONINTMAXSTRDIGITS=0 python3`` to disable the limitation.
4840+
* :option:`-X int_max_str_digits <-X>`, e.g.
4841+
``python3 -X int_max_str_digits=640``
4842+
* :data:`sys.flags.int_max_str_digits` contains the value of
4843+
:envvar:`PYTHONINTMAXSTRDIGITS` or :option:`-X int_max_str_digits <-X>`.
4844+
If both the env var and the ``-X`` option are set, the ``-X`` option takes
4845+
precedence. A value of *-1* indicates that both were unset, thus a value of
4846+
:data:`sys.int_info.default_max_str_digits` was used during initilization.
4847+
4848+
From code, you can inspect the current limit and set a new one using these
4849+
:mod:`sys` APIs:
4850+
4851+
* :func:`sys.get_int_max_str_digits` and :func:`sys.set_int_max_str_digits` are
4852+
a getter and setter for the interpreter-wide limit. Subinterpreters have
4853+
their own limit.
4854+
4855+
Information about the default and minimum can be found in :attr:`sys.int_info`:
4856+
4857+
* :data:`sys.int_info.default_max_str_digits <sys.int_info>` is the compiled-in
4858+
default limit.
4859+
* :data:`sys.int_info.str_digits_check_threshold <sys.int_info>` is the lowest
4860+
accepted value for the limit (other than 0 which disables it).
4861+
4862+
.. versionadded:: 3.7.14
4863+
4864+
.. caution::
4865+
4866+
Setting a low limit *can* lead to problems. While rare, code exists that
4867+
contains integer constants in decimal in their source that exceed the
4868+
minimum threshold. A consequence of setting the limit is that Python source
4869+
code containing decimal integer literals longer than the limit will
4870+
encounter an error during parsing, usually at startup time or import time or
4871+
even at installation time - anytime an up to date ``.pyc`` does not already
4872+
exist for the code. A workaround for source that contains such large
4873+
constants is to convert them to ``0x`` hexadecimal form as it has no limit.
4874+
4875+
Test your application thoroughly if you use a low limit. Ensure your tests
4876+
run with the limit set early via the environment or flag so that it applies
4877+
during startup and even during any installation step that may invoke Python
4878+
to precompile ``.py`` sources to ``.pyc`` files.
4879+
4880+
Recommended configuration
4881+
-------------------------
4882+
4883+
The default :data:`sys.int_info.default_max_str_digits` is expected to be
4884+
reasonable for most applications. If your application requires a different
4885+
limit, set it from your main entry point using Python version agnostic code as
4886+
these APIs were added in security patch releases in versions before 3.11.
4887+
4888+
Example::
4889+
4890+
>>> import sys
4891+
>>> if hasattr(sys, "set_int_max_str_digits"):
4892+
... upper_bound = 68000
4893+
... lower_bound = 4004
4894+
... current_limit = sys.get_int_max_str_digits()
4895+
... if current_limit == 0 or current_limit > upper_bound:
4896+
... sys.set_int_max_str_digits(upper_bound)
4897+
... elif current_limit < lower_bound:
4898+
... sys.set_int_max_str_digits(lower_bound)
4899+
4900+
If you need to disable it entirely, set it to ``0``.
4901+
4902+
47444903
.. rubric:: Footnotes
47454904

47464905
.. [1] Additional information on these special methods may be found in the Python

Doc/library/sys.rst

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,9 @@ always available.
327327
The :term:`named tuple` *flags* exposes the status of command line
328328
flags. The attributes are read only.
329329

330-
============================= =============================
330+
============================= ==============================================================================================================
331331
attribute flag
332-
============================= =============================
332+
============================= ==============================================================================================================
333333
:const:`debug` :option:`-d`
334334
:const:`inspect` :option:`-i`
335335
:const:`interactive` :option:`-i`
@@ -345,7 +345,8 @@ always available.
345345
:const:`hash_randomization` :option:`-R`
346346
:const:`dev_mode` :option:`-X` ``dev``
347347
:const:`utf8_mode` :option:`-X` ``utf8``
348-
============================= =============================
348+
:const:`int_max_str_digits` :option:`-X int_max_str_digits <-X>` (:ref:`integer string conversion length limitation <int_max_str_digits>`)
349+
============================= ==============================================================================================================
349350

350351
.. versionchanged:: 3.2
351352
Added ``quiet`` attribute for the new :option:`-q` flag.
@@ -363,6 +364,9 @@ always available.
363364
Added ``dev_mode`` attribute for the new :option:`-X` ``dev`` flag
364365
and ``utf8_mode`` attribute for the new :option:`-X` ``utf8`` flag.
365366

367+
.. versionchanged:: 3.7.14
368+
Added the ``int_max_str_digits`` attribute.
369+
366370

367371
.. data:: float_info
368372

@@ -539,6 +543,15 @@ always available.
539543

540544
.. versionadded:: 3.6
541545

546+
547+
.. function:: get_int_max_str_digits()
548+
549+
Returns the current value for the :ref:`integer string conversion length
550+
limitation <int_max_str_digits>`. See also :func:`set_int_max_str_digits`.
551+
552+
.. versionadded:: 3.7.14
553+
554+
542555
.. function:: getrefcount(object)
543556

544557
Return the reference count of the *object*. The count returned is generally one
@@ -821,19 +834,31 @@ always available.
821834

822835
.. tabularcolumns:: |l|L|
823836

824-
+-------------------------+----------------------------------------------+
825-
| Attribute | Explanation |
826-
+=========================+==============================================+
827-
| :const:`bits_per_digit` | number of bits held in each digit. Python |
828-
| | integers are stored internally in base |
829-
| | ``2**int_info.bits_per_digit`` |
830-
+-------------------------+----------------------------------------------+
831-
| :const:`sizeof_digit` | size in bytes of the C type used to |
832-
| | represent a digit |
833-
+-------------------------+----------------------------------------------+
837+
+----------------------------------------+-----------------------------------------------+
838+
| Attribute | Explanation |
839+
+========================================+===============================================+
840+
| :const:`bits_per_digit` | number of bits held in each digit. Python |
841+
| | integers are stored internally in base |
842+
| | ``2**int_info.bits_per_digit`` |
843+
+----------------------------------------+-----------------------------------------------+
844+
| :const:`sizeof_digit` | size in bytes of the C type used to |
845+
| | represent a digit |
846+
+----------------------------------------+-----------------------------------------------+
847+
| :const:`default_max_str_digits` | default value for |
848+
| | :func:`sys.get_int_max_str_digits` when it |
849+
| | is not otherwise explicitly configured. |
850+
+----------------------------------------+-----------------------------------------------+
851+
| :const:`str_digits_check_threshold` | minimum non-zero value for |
852+
| | :func:`sys.set_int_max_str_digits`, |
853+
| | :envvar:`PYTHONINTMAXSTRDIGITS`, or |
854+
| | :option:`-X int_max_str_digits <-X>`. |
855+
+----------------------------------------+-----------------------------------------------+
834856

835857
.. versionadded:: 3.1
836858

859+
.. versionchanged:: 3.7.14
860+
Added ``default_max_str_digits`` and ``str_digits_check_threshold``.
861+
837862

838863
.. data:: __interactivehook__
839864

@@ -1092,6 +1117,14 @@ always available.
10921117

10931118
.. availability:: Unix.
10941119

1120+
.. function:: set_int_max_str_digits(n)
1121+
1122+
Set the :ref:`integer string conversion length limitation
1123+
<int_max_str_digits>` used by this interpreter. See also
1124+
:func:`get_int_max_str_digits`.
1125+
1126+
.. versionadded:: 3.7.14
1127+
10951128
.. function:: setprofile(profilefunc)
10961129

10971130
.. index::

Doc/library/test.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,16 @@ The :mod:`test.support` module defines the following functions:
12071207
.. versionadded:: 3.6
12081208

12091209

1210+
.. function:: adjust_int_max_str_digits(max_digits)
1211+
1212+
This function returns a context manager that will change the global
1213+
:func:`sys.set_int_max_str_digits` setting for the duration of the
1214+
context to allow execution of test code that needs a different limit
1215+
on the number of digits when converting between an integer and string.
1216+
1217+
.. versionadded:: 3.7.14
1218+
1219+
12101220
The :mod:`test.support` module defines the following classes:
12111221

12121222
.. class:: TransientResource(exc, **kwargs)

Doc/using/cmdline.rst

Lines changed: 13 additions & 0 deletions

0 commit comments

Comments
 (0)