From 25aa726d894645646b36c60d5e14de4efe65576b Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google]" Date: Sun, 4 Sep 2022 22:01:49 +0000 Subject: [PATCH 1/6] Revert "Undo addition to PyConfig to ease backporting." This reverts commit 1ad88f551dd2dbcbcb1d8f57a4f05dfddc39d587. --- Doc/c-api/init_config.rst | 12 ++++++++++++ Include/cpython/initconfig.h | 1 + Include/internal/pycore_initconfig.h | 2 -- Lib/test/test_embed.py | 1 + Objects/longobject.c | 2 +- Python/initconfig.c | 17 ++++++++++------- Python/sysmodule.c | 2 +- 7 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index c4a342ee811ca9..9e461eca3cb12d 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -828,6 +828,18 @@ PyConfig Default: ``0``. + .. c:member:: int32_t int_max_str_digits + + If greater than 0, enable int conversion digit limitations. ``-1`` means + that :data:`sys.int_info.default_max_str_digits` will be used. + + Configured by the :option:`-X int_max_str_digits <-X>` command line + flag or the :envvar:`PYTHONINTMAXSTRDIGITS` environment varable. + + Default: ``-1``. + + .. versionadded:: 3.12 + .. c:member:: int isolated If greater than ``0``, enable isolated mode: diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index c6057a4c3ed945..2143074c5c2fd3 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -178,6 +178,7 @@ typedef struct PyConfig { wchar_t *check_hash_pycs_mode; int use_frozen_modules; int safe_path; + int32_t int_max_str_digits; /* --- Path configuration inputs ------------ */ int pathconfig_warnings; diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 6e491261d55ca6..69f88d7d1d46b8 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -170,8 +170,6 @@ extern void _Py_DumpPathConfig(PyThreadState *tstate); PyAPI_FUNC(PyObject*) _Py_Get_Getpath_CodeObject(void); -extern int _Py_global_config_int_max_str_digits; // TODO(gpshead): move this into PyConfig in 3.12 after the backports ship. - /* --- Function used for testing ---------------------------------- */ diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 70d7367ea9e64f..18ce517c474f44 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -434,6 +434,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'install_signal_handlers': 1, 'use_hash_seed': 0, 'hash_seed': 0, + 'int_max_str_digits': -1, 'faulthandler': 0, 'tracemalloc': 0, 'perf_profiling': 0, diff --git a/Objects/longobject.c b/Objects/longobject.c index cb52f82687af28..67154f931b4c50 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6196,7 +6196,7 @@ _PyLong_InitTypes(PyInterpreterState *interp) return _PyStatus_ERR("can't init int info type"); } } - interp->int_max_str_digits = _Py_global_config_int_max_str_digits; + interp->int_max_str_digits = _PyInterpreterState_GetConfig(interp)->int_max_str_digits; if (interp->int_max_str_digits == -1) { interp->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS; } diff --git a/Python/initconfig.c b/Python/initconfig.c index f18ec4068bc443..9bcf477c05c4ff 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -789,14 +789,12 @@ _PyConfig_InitCompatConfig(PyConfig *config) config->use_frozen_modules = 1; #endif config->safe_path = 0; + /* config_init_int_max_str_digits() sets default limit */ + config->int_max_str_digits = -1; config->_is_python_build = 0; config->code_debug_ranges = 1; } -/* Excluded from public struct PyConfig for backporting reasons. */ -/* default to unconfigured, _PyLong_InitTypes() does the rest */ -int _Py_global_config_int_max_str_digits = -1; - static void config_init_defaults(PyConfig *config) @@ -1021,6 +1019,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2) COPY_ATTR(safe_path); COPY_WSTRLIST(orig_argv); COPY_ATTR(_is_python_build); + COPY_ATTR(int_max_str_digits); #undef COPY_ATTR #undef COPY_WSTR_ATTR @@ -1128,6 +1127,7 @@ _PyConfig_AsDict(const PyConfig *config) SET_ITEM_INT(use_frozen_modules); SET_ITEM_INT(safe_path); SET_ITEM_INT(_is_python_build); + SET_ITEM_INT(int_max_str_digits); return dict; @@ -1781,6 +1781,9 @@ config_init_int_max_str_digits(PyConfig *config) int maxdigits; int valid = 0; + /* default to unconfigured, _PyLong_InitTypes() does the rest */ + config->int_max_str_digits = -1; + const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS"); if (env) { if (!_Py_str_to_int(env, &maxdigits)) { @@ -1794,7 +1797,7 @@ config_init_int_max_str_digits(PyConfig *config) STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD) " or 0 for unlimited."); } - _Py_global_config_int_max_str_digits = maxdigits; + config->int_max_str_digits = maxdigits; } const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits"); @@ -1813,7 +1816,7 @@ config_init_int_max_str_digits(PyConfig *config) #undef _STRINGIFY #undef STRINGIFY } - _Py_global_config_int_max_str_digits = maxdigits; + config->int_max_str_digits = maxdigits; } return _PyStatus_OK(); } @@ -1881,7 +1884,7 @@ config_read_complex_options(PyConfig *config) } } - if (_Py_global_config_int_max_str_digits < 0) { + if (config->int_max_str_digits < 0) { status = config_init_int_max_str_digits(config); if (_PyStatus_EXCEPTION(status)) { return status; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index a33abb2a8412db..43109445e75d10 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2777,7 +2777,7 @@ set_flags_from_config(PyInterpreterState *interp, PyObject *flags) SetFlag(preconfig->utf8_mode); SetFlag(config->warn_default_encoding); SetFlagObj(PyBool_FromLong(config->safe_path)); - SetFlag(_Py_global_config_int_max_str_digits); + SetFlag(config->int_max_str_digits); #undef SetFlagObj #undef SetFlag return 0; From 67c9af4270ca11353f21e297b5c272503d28376a Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google]" Date: Sun, 4 Sep 2022 22:38:23 +0000 Subject: [PATCH 2/6] Pedantically use int32_t instead of int for max. --- Include/internal/pycore_initconfig.h | 3 +++ Include/internal/pycore_interp.h | 2 +- Objects/longobject.c | 6 +++--- Python/clinic/sysmodule.c.h | 8 ++++---- Python/initconfig.c | 30 ++++++++++++++++++++++++---- Python/preconfig.c | 22 ++++++++++++++++++++ Python/sysmodule.c | 12 +++++++---- 7 files changed, 67 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 69f88d7d1d46b8..1b2ed861dc9c80 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -79,6 +79,9 @@ PyAPI_FUNC(PyStatus) _PyArgv_AsWstrList(const _PyArgv *args, PyAPI_FUNC(int) _Py_str_to_int( const char *str, int *result); +PyAPI_FUNC(int) _Py_str_to_int32( + const char *str, + int32_t *result); PyAPI_FUNC(const wchar_t*) _Py_get_xoption( const PyWideStringList *xoptions, const wchar_t *name); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index a5ddcf2d72f051..023e0ff7d3e29a 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -176,7 +176,7 @@ struct _is { struct types_state types; struct callable_cache callable_cache; - int int_max_str_digits; + int32_t int_max_str_digits; /* The following fields are here to avoid allocation during init. The data is exposed through PyInterpreterState pointer fields. diff --git a/Objects/longobject.c b/Objects/longobject.c index 67154f931b4c50..263a6a8a43f11b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1767,7 +1767,7 @@ long_to_decimal_string_internal(PyObject *aa, if (size_a >= 10 * _PY_LONG_MAX_STR_DIGITS_THRESHOLD / (3 * PyLong_SHIFT) + 2) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->int_max_str_digits; + int32_t max_str_digits = interp->int_max_str_digits; if ((max_str_digits > 0) && (max_str_digits / (3 * PyLong_SHIFT) <= (size_a - 11) / 10)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_STR, @@ -1837,7 +1837,7 @@ long_to_decimal_string_internal(PyObject *aa, } if (strlen > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->int_max_str_digits; + int32_t max_str_digits = interp->int_max_str_digits; Py_ssize_t strlen_nosign = strlen - negative; if ((max_str_digits > 0) && (strlen_nosign > max_str_digits)) { Py_DECREF(scratch); @@ -2514,7 +2514,7 @@ digit beyond the first. /* Limit the size to avoid excessive computation attacks. */ if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { PyInterpreterState *interp = _PyInterpreterState_GET(); - int max_str_digits = interp->int_max_str_digits; + int32_t max_str_digits = interp->int_max_str_digits; if ((max_str_digits > 0) && (digits > max_str_digits)) { PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_INT, max_str_digits, digits); diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 6864b8b0e03b2f..a789211df9bd2f 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -773,7 +773,7 @@ PyDoc_STRVAR(sys_set_int_max_str_digits__doc__, {"set_int_max_str_digits", _PyCFunction_CAST(sys_set_int_max_str_digits), METH_FASTCALL|METH_KEYWORDS, sys_set_int_max_str_digits__doc__}, static PyObject * -sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits); +sys_set_int_max_str_digits_impl(PyObject *module, long maxdigits); static PyObject * sys_set_int_max_str_digits(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -805,13 +805,13 @@ sys_set_int_max_str_digits(PyObject *module, PyObject *const *args, Py_ssize_t n }; #undef KWTUPLE PyObject *argsbuf[1]; - int maxdigits; + long maxdigits; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } - maxdigits = _PyLong_AsInt(args[0]); + maxdigits = PyLong_AsLong(args[0]); if (maxdigits == -1 && PyErr_Occurred()) { goto exit; } @@ -1343,4 +1343,4 @@ sys_is_stack_trampoline_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=15318cdd96b62b06 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b351d7f0c6fea5be input=a9049054013a1b77]*/ diff --git a/Python/initconfig.c b/Python/initconfig.c index 9bcf477c05c4ff..459225d844f3b3 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -1630,6 +1630,28 @@ config_wstr_to_int(const wchar_t *wstr, int *result) } +static int +config_wstr_to_int32(const wchar_t *wstr, int32_t *result) +{ +#if INT32_MAX == INT_MAX && INT32_MIN == INT_MIN + return config_wstr_to_int(wstr, result); +#else + const wchar_t *endptr = wstr; + errno = 0; + long value = wcstol(wstr, (wchar_t **)&endptr, 10); + if (*endptr != '\0' || errno == ERANGE) { + return -1; + } + if (value < INT32_MIN || value > INT32_MAX) { + return -1; + } + + *result = (int32_t)value; + return 0; +#endif +} + + static PyStatus config_read_env_vars(PyConfig *config) { @@ -1778,15 +1800,15 @@ config_init_tracemalloc(PyConfig *config) static PyStatus config_init_int_max_str_digits(PyConfig *config) { - int maxdigits; - int valid = 0; + int32_t maxdigits; + bool valid = 0; /* default to unconfigured, _PyLong_InitTypes() does the rest */ config->int_max_str_digits = -1; const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS"); if (env) { - if (!_Py_str_to_int(env, &maxdigits)) { + if (!_Py_str_to_int32(env, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } if (!valid) { @@ -1804,7 +1826,7 @@ config_init_int_max_str_digits(PyConfig *config) if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); if (sep) { - if (!config_wstr_to_int(sep + 1, &maxdigits)) { + if (!config_wstr_to_int32(sep + 1, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } } diff --git a/Python/preconfig.c b/Python/preconfig.c index 77a86d651eb0f4..c7fdd004889775 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -559,6 +559,28 @@ _Py_str_to_int(const char *str, int *result) } +int +_Py_str_to_int32(const char *str, int32_t *result) +{ +#if INT32_MAX == INT_MAX && INT32_MIN == INT_MIN + return _Py_str_to_int(str, result); +#else + const char *endptr = str; + errno = 0; + long value = strtol(str, (char **)&endptr, 10); + if (*endptr != '\0' || errno == ERANGE) { + return -1; + } + if (value < INT32_MIN || value > INT32_MAX) { + return -1; + } + + *result = (int32_t)value; + return 0; +#endif +} + + void _Py_get_env_flag(int use_environment, int *flag, const char *name) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 43109445e75d10..8d2a56f8c8dfd4 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1684,23 +1684,27 @@ sys_get_int_max_str_digits_impl(PyObject *module) /*[clinic end generated code: output=0042f5e8ae0e8631 input=8dab13e2023e60d5]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); - return PyLong_FromSsize_t(interp->int_max_str_digits); + return PyLong_FromLong(interp->int_max_str_digits); } /*[clinic input] sys.set_int_max_str_digits - maxdigits: int + maxdigits: long Set the maximum string digits limit for non-binary int<->str conversions. [clinic start generated code]*/ static PyObject * -sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits) -/*[clinic end generated code: output=734d4c2511f2a56d input=d7e3f325db6910c5]*/ +sys_set_int_max_str_digits_impl(PyObject *module, long maxdigits) +/*[clinic end generated code: output=40ea5d33a82c5c44 input=657c61a1822f6bcf]*/ { PyThreadState *tstate = _PyThreadState_GET(); if ((!maxdigits) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)) { + if (maxdigits > INT32_MAX) { + /* Silently cap to our range; already effectively unlimited. */ + maxdigits = INT32_MAX; + } tstate->interp->int_max_str_digits = maxdigits; Py_RETURN_NONE; } else { From c6e7f338469ad02ea3105f29ada678f60106e675 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google]" Date: Mon, 5 Sep 2022 01:03:20 +0000 Subject: [PATCH 3/6] Generate audit events on >threshold conversions. --- Doc/library/stdtypes.rst | 16 ++++++++++++++++ Lib/test/audit-tests.py | 23 ++++++++++++++++++----- Lib/test/test_audit.py | 27 +++++++++++++++++++++++++++ Objects/longobject.c | 6 ++++++ 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 9595a00779ba16..1d556b28f171e9 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5525,6 +5525,22 @@ Verification: .. versionadded:: 3.12 +.. audit-event:: int/digits/to_decimal value + + When a conversion from an class:`int` to decimal is estimated to be larger + than :data:`sys.int_info.str_digits_check_threshold ` digits + an :ref:`auditing event ` with the :class:`int` ``value`` as the + argument is raised. + +.. audit-event:: int/digits/from_base digits base + + When a conversion to an :class:`int` from a base other than 2, 4, 8, 16, or + 32 has more than :data:`sys.int_info.str_digits_check_threshold + ` digits an :ref:`auditing event ` with the number + of ``digits`` and ``base`` is raised. + +.. versionadded:: 3.12 + Affected APIs ------------- diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 00333cc9036a3c..819514b1fda795 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -7,6 +7,7 @@ import contextlib import os +from test import support import sys @@ -409,8 +410,6 @@ def hook(event, *args): def test_sys_getframe(): - import sys - def hook(event, args): if event.startswith("sys."): print(event, args[0].f_code.co_name) @@ -419,10 +418,24 @@ def hook(event, args): sys._getframe() -if __name__ == "__main__": - from test.support import suppress_msvcrt_asserts +def test_int_digits(): + def hook(event, args): + if event.startswith("int/digits/"): + print(event, *(hex(arg) for arg in args)) + + sys.addaudithook(hook) + + threshold = sys.int_info.str_digits_check_threshold + with support.adjust_int_max_str_digits(2*threshold): + fives = int('5' * (threshold+20)) + int('1' * (threshold*3//2), base=36) + for base in (2, 4, 8, 16, 32): # linear unaudited bases + int('1' * (threshold+1), base) + str(fives) - suppress_msvcrt_asserts() + +if __name__ == "__main__": + support.suppress_msvcrt_asserts() test = sys.argv[1] globals()[test]() diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 18426f27a2e32f..a48a5877efab5a 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -185,5 +185,32 @@ def test_sys_getframe(self): self.assertEqual(actual, expected) + def test_int_digits(self): + returncode, events, stderr = self.run_python("test_int_digits") + if returncode: + self.fail(stderr) + + if support.verbose: + print(*events, sep='\n') + actual = [(ev[0], ev[2].split(' ')) for ev in events] + + threshold = sys.int_info.str_digits_check_threshold + self.assertEqual( + actual.pop(0), + ("int/digits/from_base", [hex(threshold+20), hex(10)]), + ) + self.assertEqual( + actual.pop(0), + ("int/digits/from_base", [hex(threshold*3//2), hex(36)]), + ) + + event = actual.pop(0) + self.assertEqual(event[0], "int/digits/to_decimal") + self.assertEqual(len(event[1]), 1) + self.assertGreater(len(event[1][0]), threshold//2) + + self.assertEqual(actual, []) + + if __name__ == "__main__": unittest.main() diff --git a/Objects/longobject.c b/Objects/longobject.c index 263a6a8a43f11b..c6c6e511e97705 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1766,6 +1766,9 @@ long_to_decimal_string_internal(PyObject *aa, */ if (size_a >= 10 * _PY_LONG_MAX_STR_DIGITS_THRESHOLD / (3 * PyLong_SHIFT) + 2) { + if (PySys_Audit("int/digits/to_decimal", "O", aa) < 0) { + return -1; + } PyInterpreterState *interp = _PyInterpreterState_GET(); int32_t max_str_digits = interp->int_max_str_digits; if ((max_str_digits > 0) && @@ -2513,6 +2516,9 @@ digit beyond the first. /* Limit the size to avoid excessive computation attacks. */ if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) { + if (PySys_Audit("int/digits/from_base", "ni", digits, base) < 0) { + return NULL; + } PyInterpreterState *interp = _PyInterpreterState_GET(); int32_t max_str_digits = interp->int_max_str_digits; if ((max_str_digits > 0) && (digits > max_str_digits)) { From e51cb0226c41b4381e90006dfdc1705ba9ef80ff Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google]" Date: Mon, 5 Sep 2022 01:11:21 +0000 Subject: [PATCH 4/6] versionadded/changed to 3.11; update What's New. --- Doc/library/functions.rst | 2 +- Doc/library/json.rst | 2 +- Doc/library/stdtypes.rst | 4 ++-- Doc/library/sys.rst | 8 ++++---- Doc/library/test.rst | 2 +- Doc/using/cmdline.rst | 4 ++-- Doc/whatsnew/3.12.rst | 14 +++++--------- ...2022-08-07-16-53-38.gh-issue-95778.ch010gps.rst | 14 -------------- 8 files changed, 16 insertions(+), 34 deletions(-) delete mode 100644 Misc/NEWS.d/next/Security/2022-08-07-16-53-38.gh-issue-95778.ch010gps.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index b9cf02e87eb614..ccb691dd9f009f 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -910,7 +910,7 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.11 The delegation to :meth:`__trunc__` is deprecated. - .. versionchanged:: 3.12 + .. versionchanged:: 3.11 :class:`int` string inputs and string representations can be limited to help avoid denial of service attacks. A :exc:`ValueError` is raised when the limit is exceeded while converting a string *x* to an :class:`int` or diff --git a/Doc/library/json.rst b/Doc/library/json.rst index d05d62e78cc71e..de02be850544e2 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -258,7 +258,7 @@ Basic Usage be used to use another datatype or parser for JSON integers (e.g. :class:`float`). - .. versionchanged:: 3.12 + .. versionchanged:: 3.11 The default *parse_int* of :func:`int` now limits the maximum length of the integer string via the interpreter's :ref:`integer string conversion length limitation ` to help avoid denial diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 1d556b28f171e9..b3f0d09adaad61 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5523,7 +5523,7 @@ Verification: ... '571186405732').to_bytes(53, 'big') ... -.. versionadded:: 3.12 +.. versionadded:: 3.11 .. audit-event:: int/digits/to_decimal value @@ -5594,7 +5594,7 @@ Information about the default and minimum can be found in :attr:`sys.int_info`: * :data:`sys.int_info.str_digits_check_threshold ` is the lowest accepted value for the limit (other than 0 which disables it). -.. versionadded:: 3.12 +.. versionadded:: 3.11 .. caution:: diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index cc41b996d2dad5..4d6db2cb1b71d9 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -544,7 +544,7 @@ always available. .. versionchanged:: 3.11 Added the ``safe_path`` attribute for :option:`-P` option. - .. versionchanged:: 3.12 + .. versionchanged:: 3.11 Added the ``int_max_str_digits`` attribute. @@ -732,7 +732,7 @@ always available. Returns the current value for the :ref:`integer string conversion length limitation `. See also :func:`set_int_max_str_digits`. - .. versionadded:: 3.12 + .. versionadded:: 3.11 .. function:: getrefcount(object) @@ -1029,7 +1029,7 @@ always available. .. versionadded:: 3.1 - .. versionchanged:: 3.12 + .. versionchanged:: 3.11 Added ``default_max_str_digits`` and ``str_digits_check_threshold``. @@ -1337,7 +1337,7 @@ always available. ` used by this interpreter. See also :func:`get_int_max_str_digits`. - .. versionadded:: 3.12 + .. versionadded:: 3.11 .. function:: setprofile(profilefunc) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index eff375132318a9..53bcd7c178f947 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1018,7 +1018,7 @@ The :mod:`test.support` module defines the following functions: context to allow execution of test code that needs a different limit on the number of digits when converting between an integer and string. - .. versionadded:: 3.12 + .. versionadded:: 3.11 The :mod:`test.support` module defines the following classes: diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 6a33d98a059a09..02c9f3095b4090 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -585,7 +585,7 @@ Miscellaneous options .. versionadded:: 3.11 The ``-X frozen_modules`` option. - .. versionadded:: 3.12 + .. versionadded:: 3.11 The ``-X int_max_str_digits`` option. .. versionadded:: 3.12 @@ -775,7 +775,7 @@ conflict. interpreter's global :ref:`integer string conversion length limitation `. - .. versionadded:: 3.12 + .. versionadded:: 3.11 .. envvar:: PYTHONIOENCODING diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 70a1104127e9a8..88ce172b1982fa 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -84,15 +84,11 @@ Other Language Changes (Contributed by Serhiy Storchaka in :gh:`87995`.) * Converting between :class:`int` and :class:`str` in bases other than 2 - (binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) - now raises a :exc:`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 - `_. - This limit can be configured or disabled by environment variable, command - line flag, or :mod:`sys` APIs. See the :ref:`integer string conversion - length limitation ` documentation. The default limit - is 4300 digits in string form. + (binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) now + generates an :ref:`auditing event ` whenever the estimated number + of digits is above :data:`sys.int_info.str_digits_check_threshold + `. See the :ref:`integer string conversion length limitation + ` documentation. New Modules diff --git a/Misc/NEWS.d/next/Security/2022-08-07-16-53-38.gh-issue-95778.ch010gps.rst b/Misc/NEWS.d/next/Security/2022-08-07-16-53-38.gh-issue-95778.ch010gps.rst deleted file mode 100644 index 8eb8a34884dced..00000000000000 --- a/Misc/NEWS.d/next/Security/2022-08-07-16-53-38.gh-issue-95778.ch010gps.rst +++ /dev/null @@ -1,14 +0,0 @@ -Converting between :class:`int` and :class:`str` in bases other than 2 -(binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) now -raises a :exc:`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 -`_. - -This new limit can be configured or disabled by environment variable, command -line flag, or :mod:`sys` APIs. See the :ref:`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. From fe9f4d0db1f8dab4c3d53ea813448abbc5dbc83b Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Thu, 15 Sep 2022 15:33:59 -0700 Subject: [PATCH 5/6] Fix missing : in new docs typo. --- Doc/library/stdtypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index ad4feed4b39b86..a5ff413ec059de 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5527,7 +5527,7 @@ Verification: .. audit-event:: int/digits/to_decimal value - When a conversion from an class:`int` to decimal is estimated to be larger + When a conversion from an :class:`int` to decimal is estimated to be larger than :data:`sys.int_info.str_digits_check_threshold ` digits an :ref:`auditing event ` with the :class:`int` ``value`` as the argument is raised. From 38077ca896d6853ac90a6d1f413573cfc0ddba7f Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google LLC]" Date: Thu, 15 Sep 2022 16:11:42 -0700 Subject: [PATCH 6/6] NEWS entry about the audit hooks added. --- .../2022-09-15-16-11-38.gh-issue-96512.VrlORK.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-09-15-16-11-38.gh-issue-96512.VrlORK.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-15-16-11-38.gh-issue-96512.VrlORK.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-15-16-11-38.gh-issue-96512.VrlORK.rst new file mode 100644 index 00000000000000..8c9c0e4cca9b64 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-15-16-11-38.gh-issue-96512.VrlORK.rst @@ -0,0 +1,4 @@ +Added ``int/digits/to_decimal`` and ``int/digits/from_base`` :ref:`auditing +events ` on :class:`int` non-linear algorithm base conversions +with more than `sys.int_info.str_digits_check_threshold ` +digits.