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

+882
-22
lines changed

Doc/data/python3.7m.abi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,7 @@
18601860
<elf-symbol name='_Py_endswith__doc__' size='264' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
18611861
<elf-symbol name='_Py_expandtabs__doc__' size='173' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
18621862
<elf-symbol name='_Py_find__doc__' size='239' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
1863+
<elf-symbol name='_Py_global_config_int_max_str_digits' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
18631864
<elf-symbol name='_Py_index__doc__' size='270' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
18641865
<elf-symbol name='_Py_isalnum__doc__' size='132' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
18651866
<elf-symbol name='_Py_isalpha__doc__' size='130' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -11958,6 +11959,9 @@
1195811959
<data-member access='public' layout-offset-in-bits='11776'>
1195911960
<var-decl name='gilstate' type-id='type-id-600' visibility='default' filepath='../gpshead/Include/internal/pystate.h' line='105' column='1'/>
1196011961
</data-member>
11962+
<data-member access='public' layout-offset-in-bits='12096'>
11963+
<var-decl name='int_max_str_digits' type-id='type-id-7' visibility='default' filepath='../gpshead/Include/internal/pystate.h' line='109' column='1'/>
11964+
</data-member>
1196111965
</class-decl>
1196211966
<class-decl name='pyinterpreters' size-in-bits='256' is-struct='yes' visibility='default' filepath='../gpshead/Include/internal/pystate.h' line='83' column='1' id='type-id-596'>
1196311967
<data-member access='public' layout-offset-in-bits='0'>

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
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ Miscellaneous options
432432
* ``-X showalloccount`` to output the total count of allocated objects for
433433
each type when the program finishes. This only works when Python was built with
434434
``COUNT_ALLOCS`` defined.
435+
* ``-X int_max_str_digits`` configures the :ref:`integer string conversion
436+
length limitation <int_max_str_digits>`. See also
437+
:envvar:`PYTHONINTMAXSTRDIGITS`.
435438
* ``-X importtime`` to show how long each import takes. It shows module
436439
name, cumulative time (including nested imports) and self time (excluding
437440
nested imports). Note that its output may be broken in multi-threaded
@@ -474,6 +477,9 @@ Miscellaneous options
474477
.. versionadded:: 3.7
475478
The ``-X importtime``, ``-X dev`` and ``-X utf8`` options.
476479

480+
.. versionadded:: 3.7.14
481+
The ``-X int_max_str_digits`` option.
482+
477483

478484
Options you shouldn't use
479485
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -618,6 +624,13 @@ conflict.
618624

619625
.. versionadded:: 3.2.3
620626

627+
.. envvar:: PYTHONINTMAXSTRDIGITS
628+
629+
If this variable is set to an integer, it is used to configure the
630+
interpreter's global :ref:`integer string conversion length limitation
631+
<int_max_str_digits>`.
632+
633+
.. versionadded:: 3.7.14
621634

622635
.. envvar:: PYTHONIOENCODING
623636

0 commit comments

Comments
 (0)