diff --git a/00189-use-rpm-wheels.patch b/00189-use-rpm-wheels.patch index 522ac6aa9922dc1332551797b99b7004ad8ae5df..1faeec46ddc2b5a4af7f73620a3d1fade70ea4c0 100644 --- a/00189-use-rpm-wheels.patch +++ b/00189-use-rpm-wheels.patch @@ -12,7 +12,7 @@ We might eventually pursuit upstream support, but it's low prio 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py -index f3152a55d4..f58dab1800 100644 +index 38bb421..413c1b3 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -1,6 +1,7 @@ @@ -24,16 +24,16 @@ index f3152a55d4..f58dab1800 100644 import sys import runpy import tempfile -@@ -8,10 +9,24 @@ import tempfile +@@ -9,10 +10,24 @@ import subprocess __all__ = ["version", "bootstrap"] +_WHEEL_DIR = "/usr/share/python-wheels/" --_SETUPTOOLS_VERSION = "47.1.0" +-_SETUPTOOLS_VERSION = "49.2.1" +_wheels = {} --_PIP_VERSION = "20.1.1" +-_PIP_VERSION = "20.2.3" +def _get_most_recent_wheel_version(pkg): + prefix = os.path.join(_WHEEL_DIR, "{}-".format(pkg)) + _wheels[pkg] = {} @@ -51,7 +51,7 @@ index f3152a55d4..f58dab1800 100644 _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), -@@ -105,13 +120,10 @@ def _bootstrap(*, root=None, upgrade=False, user=False, +@@ -102,13 +117,10 @@ def _bootstrap(*, root=None, upgrade=False, user=False, # additional paths that need added to sys.path additional_paths = [] for project, version, py_tag in _PROJECTS: @@ -69,3 +69,6 @@ index f3152a55d4..f58dab1800 100644 additional_paths.append(os.path.join(tmpdir, wheel_name)) +-- +1.8.3.1 + diff --git a/CVE-2020-27619.patch b/CVE-2020-27619.patch deleted file mode 100644 index 1ba95986166fa7f2effc1b2553b0a496dee5658d..0000000000000000000000000000000000000000 --- a/CVE-2020-27619.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 43e523103886af66d6c27cd72431b5d9d14cd2a9 Mon Sep 17 00:00:00 2001 -From: "Miss Skeleton (bot)" <31488909+miss-islington@users.noreply.github.com> -Date: Mon, 19 Oct 2020 19:38:40 -0700 -Subject: [PATCH] bpo-41944: No longer call eval() on content received via HTTP - in the CJK codec tests (GH-22566) (GH-22578) - -(cherry picked from commit 2ef5caa58febc8968e670e39e3d37cf8eef3cab8) - -https://github.com/python/cpython/commit/43e523103886af66d6c27cd72431b5d9d14cd2a9 -reason:CVE-2020-27619 - -Co-authored-by: Serhiy Storchaka ---- - Lib/test/multibytecodec_support.py | 22 +++++++------------ - .../2020-10-05-17-43-46.bpo-41944.rf1dYb.rst | 1 + - 2 files changed, 9 insertions(+), 14 deletions(-) - create mode 100644 Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst - -diff --git a/Lib/test/multibytecodec_support.py b/Lib/test/multibytecodec_support.py -index cca8af67d6d1d..f76c0153f5ecf 100644 ---- a/Lib/test/multibytecodec_support.py -+++ b/Lib/test/multibytecodec_support.py -@@ -305,29 +305,23 @@ def test_mapping_file(self): - self._test_mapping_file_plain() - - def _test_mapping_file_plain(self): -- unichrs = lambda s: ''.join(map(chr, map(eval, s.split('+')))) -+ def unichrs(s): -+ return ''.join(chr(int(x, 16)) for x in s.split('+')) -+ - urt_wa = {} - - with self.open_mapping_file() as f: - for line in f: - if not line: - break -- data = line.split('#')[0].strip().split() -+ data = line.split('#')[0].split() - if len(data) != 2: - continue - -- csetval = eval(data[0]) -- if csetval <= 0x7F: -- csetch = bytes([csetval & 0xff]) -- elif csetval >= 0x1000000: -- csetch = bytes([(csetval >> 24), ((csetval >> 16) & 0xff), -- ((csetval >> 8) & 0xff), (csetval & 0xff)]) -- elif csetval >= 0x10000: -- csetch = bytes([(csetval >> 16), ((csetval >> 8) & 0xff), -- (csetval & 0xff)]) -- elif csetval >= 0x100: -- csetch = bytes([(csetval >> 8), (csetval & 0xff)]) -- else: -+ if data[0][:2] != '0x': -+ self.fail(f"Invalid line: {line!r}") -+ csetch = bytes.fromhex(data[0][2:]) -+ if len(csetch) == 1 and 0x80 <= csetch[0]: - continue - - unich = unichrs(data[1]) -diff --git a/Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst b/Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst -new file mode 100644 -index 0000000000000..4f9782f1c85af ---- /dev/null -+++ b/Misc/NEWS.d/next/Tests/2020-10-05-17-43-46.bpo-41944.rf1dYb.rst -@@ -0,0 +1 @@ -+Tests for CJK codecs no longer call ``eval()`` on content received via HTTP. diff --git a/CVE-2021-3177.patch b/CVE-2021-3177.patch deleted file mode 100644 index da973292a3db5a93286772464205527f352529ec..0000000000000000000000000000000000000000 --- a/CVE-2021-3177.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 298cc0231a271b5d5c6d55273297b9541353ecc3 Mon Sep 17 00:00:00 2001 -From: Benjamin Peterson -Date: Mon, 18 Jan 2021 09:28:15 -0600 -Subject: [PATCH] closes bpo-42938: Replace snprintf with Python unicode - formatting in ctypes param reprs. - -https://github.com/python/cpython/commit/916610ef90a0d0761f08747f7b0905541f0977c7 -reason:CVE-2021-3177 - ---- - Lib/ctypes/test/test_parameters.py | 43 ++++++++++++++++ - .../2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst | 2 + - Modules/_ctypes/callproc.c | 51 +++++++------------ - 3 files changed, 64 insertions(+), 32 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst - -diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py -index e4c25fd880cef..531894fdec838 100644 ---- a/Lib/ctypes/test/test_parameters.py -+++ b/Lib/ctypes/test/test_parameters.py -@@ -201,6 +201,49 @@ def __dict__(self): - with self.assertRaises(ZeroDivisionError): - WorseStruct().__setstate__({}, b'foo') - -+ def test_parameter_repr(self): -+ from ctypes import ( -+ c_bool, -+ c_char, -+ c_wchar, -+ c_byte, -+ c_ubyte, -+ c_short, -+ c_ushort, -+ c_int, -+ c_uint, -+ c_long, -+ c_ulong, -+ c_longlong, -+ c_ulonglong, -+ c_float, -+ c_double, -+ c_longdouble, -+ c_char_p, -+ c_wchar_p, -+ c_void_p, -+ ) -+ self.assertRegex(repr(c_bool.from_param(True)), r"^$") -+ self.assertEqual(repr(c_char.from_param(97)), "") -+ self.assertRegex(repr(c_wchar.from_param('a')), r"^$") -+ self.assertEqual(repr(c_byte.from_param(98)), "") -+ self.assertEqual(repr(c_ubyte.from_param(98)), "") -+ self.assertEqual(repr(c_short.from_param(511)), "") -+ self.assertEqual(repr(c_ushort.from_param(511)), "") -+ self.assertRegex(repr(c_int.from_param(20000)), r"^$") -+ self.assertRegex(repr(c_uint.from_param(20000)), r"^$") -+ self.assertRegex(repr(c_long.from_param(20000)), r"^$") -+ self.assertRegex(repr(c_ulong.from_param(20000)), r"^$") -+ self.assertRegex(repr(c_longlong.from_param(20000)), r"^$") -+ self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^$") -+ self.assertEqual(repr(c_float.from_param(1.5)), "") -+ self.assertEqual(repr(c_double.from_param(1.5)), "") -+ self.assertEqual(repr(c_double.from_param(1e300)), "") -+ self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^$") -+ self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^$") -+ self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^$") -+ self.assertRegex(repr(c_void_p.from_param(0x12)), r"^$") -+ - ################################################################ - - if __name__ == '__main__': -diff --git a/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst -new file mode 100644 -index 0000000000000..7df65a156feab ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst -@@ -0,0 +1,2 @@ -+Avoid static buffers when computing the repr of :class:`ctypes.c_double` and -+:class:`ctypes.c_longdouble` values. -diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c -index 40a05a44edd4c..56ccc2f1e0b5d 100644 ---- a/Modules/_ctypes/callproc.c -+++ b/Modules/_ctypes/callproc.c -@@ -487,58 +487,47 @@ is_literal_char(unsigned char c) - static PyObject * - PyCArg_repr(PyCArgObject *self) - { -- char buffer[256]; - switch(self->tag) { - case 'b': - case 'B': -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, self->value.b); -- break; - case 'h': - case 'H': -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, self->value.h); -- break; - case 'i': - case 'I': -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, self->value.i); -- break; - case 'l': - case 'L': -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, self->value.l); -- break; - - case 'q': - case 'Q': -- sprintf(buffer, --#ifdef MS_WIN32 -- "", --#else -- "", --#endif -+ return PyUnicode_FromFormat("", - self->tag, self->value.q); -- break; - case 'd': -- sprintf(buffer, "", -- self->tag, self->value.d); -- break; -- case 'f': -- sprintf(buffer, "", -- self->tag, self->value.f); -- break; -- -+ case 'f': { -+ PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d); -+ if (f == NULL) { -+ return NULL; -+ } -+ PyObject *result = PyUnicode_FromFormat("", self->tag, f); -+ Py_DECREF(f); -+ return result; -+ } - case 'c': - if (is_literal_char((unsigned char)self->value.c)) { -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, self->value.c); - } - else { -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, (unsigned char)self->value.c); - } -- break; - - /* Hm, are these 'z' and 'Z' codes useful at all? - Shouldn't they be replaced by the functionality of c_string -@@ -547,22 +536,20 @@ PyCArg_repr(PyCArgObject *self) - case 'z': - case 'Z': - case 'P': -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - self->tag, self->value.p); - break; - - default: - if (is_literal_char((unsigned char)self->tag)) { -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - (unsigned char)self->tag, (void *)self); - } - else { -- sprintf(buffer, "", -+ return PyUnicode_FromFormat("", - (unsigned char)self->tag, (void *)self); - } -- break; - } -- return PyUnicode_FromString(buffer); - } - - static PyMemberDef PyCArgType_members[] = { diff --git a/Python-3.8.5.tar.xz b/Python-3.8.8.tar.xz similarity index 66% rename from Python-3.8.5.tar.xz rename to Python-3.8.8.tar.xz index cc9efe2603384e4d57123c1d6f3bfe55cb7a76e5..070a14e5bd45996e350fda6137765aa9f9eae017 100644 Binary files a/Python-3.8.5.tar.xz and b/Python-3.8.8.tar.xz differ diff --git a/backport-CVE-2021-23336.patch b/backport-CVE-2021-23336.patch deleted file mode 100644 index 15b8ba0f26f755e5357900b3c546834cae9d4046..0000000000000000000000000000000000000000 --- a/backport-CVE-2021-23336.patch +++ /dev/null @@ -1,536 +0,0 @@ -From e3110c3cfbb7daa690d54d0eff6c264c870a71bf Mon Sep 17 00:00:00 2001 -From: Senthil Kumaran -Date: Mon, 15 Feb 2021 10:15:02 -0800 -Subject: [PATCH] [3.8] bpo-42967: only use '&' as a query string separator - (GH-24297) (#24529) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -* bpo-42967: only use '&' as a query string separator (#24297) - -bpo-42967: [security] Address a web cache-poisoning issue reported in -urllib.parse.parse_qsl(). - -urllib.parse will only us "&" as query string separator by default -instead of both ";" and "&" as allowed in earlier versions. An optional -argument seperator with default value "&" is added to specify the -separator. - -Co-authored-by: Éric Araujo -Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> -Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> -Co-authored-by: Éric Araujo -(cherry picked from commit fcbe0cb04d35189401c0c880ebfb4311e952d776) - -* [3.8] bpo-42967: only use '&' as a query string separator (GH-24297) - -bpo-42967: [security] Address a web cache-poisoning issue reported in urllib.parse.parse_qsl(). - -urllib.parse will only us "&" as query string separator by default instead of both ";" and "&" as allowed in earlier versions. An optional argument seperator with default value "&" is added to specify the separator. - -Co-authored-by: Éric Araujo -Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> -Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> -Co-authored-by: Éric Araujo . -(cherry picked from commit fcbe0cb04d35189401c0c880ebfb4311e952d776) - -Co-authored-by: Adam Goldschmidt - -* Update correct version information. - -* fix docs and make logic clearer - -Co-authored-by: Adam Goldschmidt -Co-authored-by: Fidget-Spinner <28750310+Fidget-Spinner@users.noreply.github.com> ---- - Doc/library/cgi.rst | 11 ++- - Doc/library/urllib.parse.rst | 22 +++++- - Doc/whatsnew/3.6.rst | 13 ++++ - Doc/whatsnew/3.7.rst | 13 ++++ - Doc/whatsnew/3.8.rst | 13 ++++ - Lib/cgi.py | 23 ++++--- - Lib/test/test_cgi.py | 29 ++++++-- - Lib/test/test_urlparse.py | 68 +++++++++++++------ - Lib/urllib/parse.py | 19 ++++-- - .../2021-02-14-15-59-16.bpo-42967.YApqDS.rst | 1 + - 10 files changed, 166 insertions(+), 46 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2021-02-14-15-59-16.bpo-42967.YApqDS.rst - -diff --git a/Doc/library/cgi.rst b/Doc/library/cgi.rst -index 4048592e7361f..880074bed6026 100644 ---- a/Doc/library/cgi.rst -+++ b/Doc/library/cgi.rst -@@ -277,14 +277,16 @@ These are useful if you want more control, or if you want to employ some of the - algorithms implemented in this module in other circumstances. - - --.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False) -+.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False, separator="&") - - Parse a query in the environment or from a file (the file defaults to -- ``sys.stdin``). The *keep_blank_values* and *strict_parsing* parameters are -+ ``sys.stdin``). The *keep_blank_values*, *strict_parsing* and *separator* parameters are - passed to :func:`urllib.parse.parse_qs` unchanged. - -+ .. versionchanged:: 3.8.8 -+ Added the *separator* parameter. - --.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace") -+.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator="&") - - Parse input of type :mimetype:`multipart/form-data` (for file uploads). - Arguments are *fp* for the input file, *pdict* for a dictionary containing -@@ -303,6 +305,9 @@ algorithms implemented in this module in other circumstances. - Added the *encoding* and *errors* parameters. For non-file fields, the - value is now a list of strings, not bytes. - -+ .. versionchanged:: 3.8.8 -+ Added the *separator* parameter. -+ - - .. function:: parse_header(string) - -diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst -index 25e5cc1a6ce0b..fcad7076e6c77 100644 ---- a/Doc/library/urllib.parse.rst -+++ b/Doc/library/urllib.parse.rst -@@ -165,7 +165,7 @@ or on combining URL components into a URL string. - now raise :exc:`ValueError`. - - --.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None) -+.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&') - - Parse a query string given as a string argument (data of type - :mimetype:`application/x-www-form-urlencoded`). Data are returned as a -@@ -190,6 +190,9 @@ or on combining URL components into a URL string. - read. If set, then throws a :exc:`ValueError` if there are more than - *max_num_fields* fields read. - -+ The optional argument *separator* is the symbol to use for separating the -+ query arguments. It defaults to ``&``. -+ - Use the :func:`urllib.parse.urlencode` function (with the ``doseq`` - parameter set to ``True``) to convert such dictionaries into query - strings. -@@ -201,8 +204,14 @@ or on combining URL components into a URL string. - .. versionchanged:: 3.8 - Added *max_num_fields* parameter. - -+ .. versionchanged:: 3.8.8 -+ Added *separator* parameter with the default value of ``&``. Python -+ versions earlier than Python 3.8.8 allowed using both ``;`` and ``&`` as -+ query parameter separator. This has been changed to allow only a single -+ separator key, with ``&`` as the default separator. -+ - --.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None) -+.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&') - - Parse a query string given as a string argument (data of type - :mimetype:`application/x-www-form-urlencoded`). Data are returned as a list of -@@ -226,6 +235,9 @@ or on combining URL components into a URL string. - read. If set, then throws a :exc:`ValueError` if there are more than - *max_num_fields* fields read. - -+ The optional argument *separator* is the symbol to use for separating the -+ query arguments. It defaults to ``&``. -+ - Use the :func:`urllib.parse.urlencode` function to convert such lists of pairs into - query strings. - -@@ -235,6 +247,12 @@ or on combining URL components into a URL string. - .. versionchanged:: 3.8 - Added *max_num_fields* parameter. - -+ .. versionchanged:: 3.8.8 -+ Added *separator* parameter with the default value of ``&``. Python -+ versions earlier than Python 3.8.8 allowed using both ``;`` and ``&`` as -+ query parameter separator. This has been changed to allow only a single -+ separator key, with ``&`` as the default separator. -+ - - .. function:: urlunparse(parts) - -diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst -index 85a6657fdfbda..03a877a3d9178 100644 ---- a/Doc/whatsnew/3.6.rst -+++ b/Doc/whatsnew/3.6.rst -@@ -2443,3 +2443,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more - details, see the documentation for ``loop.create_datagram_endpoint()``. - (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in - :issue:`37228`.) -+ -+Notable changes in Python 3.6.13 -+================================ -+ -+Earlier Python versions allowed using both ``;`` and ``&`` as -+query parameter separators in :func:`urllib.parse.parse_qs` and -+:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with -+newer W3C recommendations, this has been changed to allow only a single -+separator key, with ``&`` as the default. This change also affects -+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected -+functions internally. For more details, please see their respective -+documentation. -+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) -diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst -index 4933cba3990b1..824dc13e0c6fd 100644 ---- a/Doc/whatsnew/3.7.rst -+++ b/Doc/whatsnew/3.7.rst -@@ -2556,3 +2556,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more - details, see the documentation for ``loop.create_datagram_endpoint()``. - (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in - :issue:`37228`.) -+ -+Notable changes in Python 3.7.10 -+================================ -+ -+Earlier Python versions allowed using both ``;`` and ``&`` as -+query parameter separators in :func:`urllib.parse.parse_qs` and -+:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with -+newer W3C recommendations, this has been changed to allow only a single -+separator key, with ``&`` as the default. This change also affects -+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected -+functions internally. For more details, please see their respective -+documentation. -+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) -diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst -index 1a192800b2f02..632ccc1f2c40a 100644 ---- a/Doc/whatsnew/3.8.rst -+++ b/Doc/whatsnew/3.8.rst -@@ -2251,3 +2251,16 @@ The constant values of future flags in the :mod:`__future__` module - are updated in order to prevent collision with compiler flags. Previously - ``PyCF_ALLOW_TOP_LEVEL_AWAIT`` was clashing with ``CO_FUTURE_DIVISION``. - (Contributed by Batuhan Taskaya in :issue:`39562`) -+ -+Notable changes in Python 3.8.8 -+=============================== -+ -+Earlier Python versions allowed using both ``;`` and ``&`` as -+query parameter separators in :func:`urllib.parse.parse_qs` and -+:func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with -+newer W3C recommendations, this has been changed to allow only a single -+separator key, with ``&`` as the default. This change also affects -+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected -+functions internally. For more details, please see their respective -+documentation. -+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) -diff --git a/Lib/cgi.py b/Lib/cgi.py -index 77ab703cc0360..1e880e51848af 100755 ---- a/Lib/cgi.py -+++ b/Lib/cgi.py -@@ -115,7 +115,8 @@ def closelog(): - # 0 ==> unlimited input - maxlen = 0 - --def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0): -+def parse(fp=None, environ=os.environ, keep_blank_values=0, -+ strict_parsing=0, separator='&'): - """Parse a query in the environment or from a file (default stdin) - - Arguments, all optional: -@@ -134,6 +135,9 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0): - strict_parsing: flag indicating what to do with parsing errors. - If false (the default), errors are silently ignored. - If true, errors raise a ValueError exception. -+ -+ separator: str. The symbol to use for separating the query arguments. -+ Defaults to &. - """ - if fp is None: - fp = sys.stdin -@@ -154,7 +158,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0): - if environ['REQUEST_METHOD'] == 'POST': - ctype, pdict = parse_header(environ['CONTENT_TYPE']) - if ctype == 'multipart/form-data': -- return parse_multipart(fp, pdict) -+ return parse_multipart(fp, pdict, separator=separator) - elif ctype == 'application/x-www-form-urlencoded': - clength = int(environ['CONTENT_LENGTH']) - if maxlen and clength > maxlen: -@@ -178,10 +182,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0): - qs = "" - environ['QUERY_STRING'] = qs # XXX Shouldn't, really - return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing, -- encoding=encoding) -+ encoding=encoding, separator=separator) - - --def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"): -+def parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator='&'): - """Parse multipart input. - - Arguments: -@@ -205,7 +209,7 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"): - except KeyError: - pass - fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors, -- environ={'REQUEST_METHOD': 'POST'}) -+ environ={'REQUEST_METHOD': 'POST'}, separator=separator) - return {k: fs.getlist(k) for k in fs} - - def _parseparam(s): -@@ -315,7 +319,7 @@ class FieldStorage: - def __init__(self, fp=None, headers=None, outerboundary=b'', - environ=os.environ, keep_blank_values=0, strict_parsing=0, - limit=None, encoding='utf-8', errors='replace', -- max_num_fields=None): -+ max_num_fields=None, separator='&'): - """Constructor. Read multipart/* until last part. - - Arguments, all optional: -@@ -363,6 +367,7 @@ def __init__(self, fp=None, headers=None, outerboundary=b'', - self.keep_blank_values = keep_blank_values - self.strict_parsing = strict_parsing - self.max_num_fields = max_num_fields -+ self.separator = separator - if 'REQUEST_METHOD' in environ: - method = environ['REQUEST_METHOD'].upper() - self.qs_on_post = None -@@ -589,7 +594,7 @@ def read_urlencoded(self): - query = urllib.parse.parse_qsl( - qs, self.keep_blank_values, self.strict_parsing, - encoding=self.encoding, errors=self.errors, -- max_num_fields=self.max_num_fields) -+ max_num_fields=self.max_num_fields, separator=self.separator) - self.list = [MiniFieldStorage(key, value) for key, value in query] - self.skip_lines() - -@@ -605,7 +610,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing): - query = urllib.parse.parse_qsl( - self.qs_on_post, self.keep_blank_values, self.strict_parsing, - encoding=self.encoding, errors=self.errors, -- max_num_fields=self.max_num_fields) -+ max_num_fields=self.max_num_fields, separator=self.separator) - self.list.extend(MiniFieldStorage(key, value) for key, value in query) - - klass = self.FieldStorageClass or self.__class__ -@@ -649,7 +654,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing): - else self.limit - self.bytes_read - part = klass(self.fp, headers, ib, environ, keep_blank_values, - strict_parsing, limit, -- self.encoding, self.errors, max_num_fields) -+ self.encoding, self.errors, max_num_fields, self.separator) - - if max_num_fields is not None: - max_num_fields -= 1 -diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py -index 101942de947fb..4e1506a6468b9 100644 ---- a/Lib/test/test_cgi.py -+++ b/Lib/test/test_cgi.py -@@ -53,12 +53,9 @@ def do_test(buf, method): - ("", ValueError("bad query field: ''")), - ("&", ValueError("bad query field: ''")), - ("&&", ValueError("bad query field: ''")), -- (";", ValueError("bad query field: ''")), -- (";&;", ValueError("bad query field: ''")), - # Should the next few really be valid? - ("=", {}), - ("=&=", {}), -- ("=;=", {}), - # This rest seem to make sense - ("=a", {'': ['a']}), - ("&=a", ValueError("bad query field: ''")), -@@ -73,8 +70,6 @@ def do_test(buf, method): - ("a=a+b&b=b+c", {'a': ['a b'], 'b': ['b c']}), - ("a=a+b&a=b+a", {'a': ['a b', 'b a']}), - ("x=1&y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), -- ("x=1;y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), -- ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), - ("Hbc5161168c542333633315dee1182227:key_store_seqid=400006&cuyer=r&view=bustomer&order_id=0bb2e248638833d48cb7fed300000f1b&expire=964546263&lobale=en-US&kid=130003.300038&ss=env", - {'Hbc5161168c542333633315dee1182227:key_store_seqid': ['400006'], - 'cuyer': ['r'], -@@ -201,6 +196,30 @@ def test_strict(self): - else: - self.assertEqual(fs.getvalue(key), expect_val[0]) - -+ def test_separator(self): -+ parse_semicolon = [ -+ ("x=1;y=2.0", {'x': ['1'], 'y': ['2.0']}), -+ ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), -+ (";", ValueError("bad query field: ''")), -+ (";;", ValueError("bad query field: ''")), -+ ("=;a", ValueError("bad query field: 'a'")), -+ (";b=a", ValueError("bad query field: ''")), -+ ("b;=a", ValueError("bad query field: 'b'")), -+ ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), -+ ("a=a+b;a=b+a", {'a': ['a b', 'b a']}), -+ ] -+ for orig, expect in parse_semicolon: -+ env = {'QUERY_STRING': orig} -+ fs = cgi.FieldStorage(separator=';', environ=env) -+ if isinstance(expect, dict): -+ for key in expect.keys(): -+ expect_val = expect[key] -+ self.assertIn(key, fs) -+ if len(expect_val) > 1: -+ self.assertEqual(fs.getvalue(key), expect_val) -+ else: -+ self.assertEqual(fs.getvalue(key), expect_val[0]) -+ - def test_log(self): - cgi.log("Testing") - -diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index 4ae6ed33858ce..90c8d6922629e 100644 ---- a/Lib/test/test_urlparse.py -+++ b/Lib/test/test_urlparse.py -@@ -32,16 +32,10 @@ - (b"&a=b", [(b'a', b'b')]), - (b"a=a+b&b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), - (b"a=1&a=2", [(b'a', b'1'), (b'a', b'2')]), -- (";", []), -- (";;", []), -- (";a=b", [('a', 'b')]), -- ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]), -- ("a=1;a=2", [('a', '1'), ('a', '2')]), -- (b";", []), -- (b";;", []), -- (b";a=b", [(b'a', b'b')]), -- (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), -- (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]), -+ (";a=b", [(';a', 'b')]), -+ ("a=a+b;b=b+c", [('a', 'a b;b=b c')]), -+ (b";a=b", [(b';a', b'b')]), -+ (b"a=a+b;b=b+c", [(b'a', b'a b;b=b c')]), - ] - - # Each parse_qs testcase is a two-tuple that contains -@@ -68,16 +62,10 @@ - (b"&a=b", {b'a': [b'b']}), - (b"a=a+b&b=b+c", {b'a': [b'a b'], b'b': [b'b c']}), - (b"a=1&a=2", {b'a': [b'1', b'2']}), -- (";", {}), -- (";;", {}), -- (";a=b", {'a': ['b']}), -- ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), -- ("a=1;a=2", {'a': ['1', '2']}), -- (b";", {}), -- (b";;", {}), -- (b";a=b", {b'a': [b'b']}), -- (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}), -- (b"a=1;a=2", {b'a': [b'1', b'2']}), -+ (";a=b", {';a': ['b']}), -+ ("a=a+b;b=b+c", {'a': ['a b;b=b c']}), -+ (b";a=b", {b';a': [b'b']}), -+ (b"a=a+b;b=b+c", {b'a':[ b'a b;b=b c']}), - ] - - class UrlParseTestCase(unittest.TestCase): -@@ -884,10 +872,46 @@ def test_parse_qsl_encoding(self): - def test_parse_qsl_max_num_fields(self): - with self.assertRaises(ValueError): - urllib.parse.parse_qs('&'.join(['a=a']*11), max_num_fields=10) -- with self.assertRaises(ValueError): -- urllib.parse.parse_qs(';'.join(['a=a']*11), max_num_fields=10) - urllib.parse.parse_qs('&'.join(['a=a']*10), max_num_fields=10) - -+ def test_parse_qs_separator(self): -+ parse_qs_semicolon_cases = [ -+ (";", {}), -+ (";;", {}), -+ (";a=b", {'a': ['b']}), -+ ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), -+ ("a=1;a=2", {'a': ['1', '2']}), -+ (b";", {}), -+ (b";;", {}), -+ (b";a=b", {b'a': [b'b']}), -+ (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}), -+ (b"a=1;a=2", {b'a': [b'1', b'2']}), -+ ] -+ for orig, expect in parse_qs_semicolon_cases: -+ with self.subTest(f"Original: {orig!r}, Expected: {expect!r}"): -+ result = urllib.parse.parse_qs(orig, separator=';') -+ self.assertEqual(result, expect, "Error parsing %r" % orig) -+ -+ -+ def test_parse_qsl_separator(self): -+ parse_qsl_semicolon_cases = [ -+ (";", []), -+ (";;", []), -+ (";a=b", [('a', 'b')]), -+ ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]), -+ ("a=1;a=2", [('a', '1'), ('a', '2')]), -+ (b";", []), -+ (b";;", []), -+ (b";a=b", [(b'a', b'b')]), -+ (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), -+ (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]), -+ ] -+ for orig, expect in parse_qsl_semicolon_cases: -+ with self.subTest(f"Original: {orig!r}, Expected: {expect!r}"): -+ result = urllib.parse.parse_qsl(orig, separator=';') -+ self.assertEqual(result, expect, "Error parsing %r" % orig) -+ -+ - def test_urlencode_sequences(self): - # Other tests incidentally urlencode things; test non-covered cases: - # Sequence and object values. -diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index 95be7181133b4..0c1c94f5fc986 100644 ---- a/Lib/urllib/parse.py -+++ b/Lib/urllib/parse.py -@@ -650,7 +650,7 @@ def unquote(string, encoding='utf-8', errors='replace'): - - - def parse_qs(qs, keep_blank_values=False, strict_parsing=False, -- encoding='utf-8', errors='replace', max_num_fields=None): -+ encoding='utf-8', errors='replace', max_num_fields=None, separator='&'): - """Parse a query given as a string argument. - - Arguments: -@@ -674,12 +674,15 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False, - max_num_fields: int. If set, then throws a ValueError if there - are more than n fields read by parse_qsl(). - -+ separator: str. The symbol to use for separating the query arguments. -+ Defaults to &. -+ - Returns a dictionary. - """ - parsed_result = {} - pairs = parse_qsl(qs, keep_blank_values, strict_parsing, - encoding=encoding, errors=errors, -- max_num_fields=max_num_fields) -+ max_num_fields=max_num_fields, separator=separator) - for name, value in pairs: - if name in parsed_result: - parsed_result[name].append(value) -@@ -689,7 +692,7 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False, - - - def parse_qsl(qs, keep_blank_values=False, strict_parsing=False, -- encoding='utf-8', errors='replace', max_num_fields=None): -+ encoding='utf-8', errors='replace', max_num_fields=None, separator='&'): - """Parse a query given as a string argument. - - Arguments: -@@ -712,19 +715,25 @@ def parse_qsl(qs, keep_blank_values=False, strict_parsing=False, - max_num_fields: int. If set, then throws a ValueError - if there are more than n fields read by parse_qsl(). - -+ separator: str. The symbol to use for separating the query arguments. -+ Defaults to &. -+ - Returns a list, as G-d intended. - """ - qs, _coerce_result = _coerce_args(qs) - -+ if not separator or (not isinstance(separator, (str, bytes))): -+ raise ValueError("Separator must be of type string or bytes.") -+ - # If max_num_fields is defined then check that the number of fields - # is less than max_num_fields. This prevents a memory exhaustion DOS - # attack via post bodies with many fields. - if max_num_fields is not None: -- num_fields = 1 + qs.count('&') + qs.count(';') -+ num_fields = 1 + qs.count(separator) - if max_num_fields < num_fields: - raise ValueError('Max number of fields exceeded') - -- pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] -+ pairs = [s1 for s1 in qs.split(separator)] - r = [] - for name_value in pairs: - if not name_value and not strict_parsing: diff --git a/backport-Fix-reference-leak-when-Thread-is-never-joined.patch b/backport-Fix-reference-leak-when-Thread-is-never-joined.patch new file mode 100644 index 0000000000000000000000000000000000000000..eadee0555bcbb582b1f812a9ccfb960a0e8d1366 --- /dev/null +++ b/backport-Fix-reference-leak-when-Thread-is-never-joined.patch @@ -0,0 +1,95 @@ +From b30b25b26663fb6070b8ed86fe3a20dcb557d05d Mon Sep 17 00:00:00 2001 +From: Antoine Pitrou +Date: Sat, 15 May 2021 11:51:20 +0200 +Subject: [PATCH] [3.9] bpo-37788: Fix reference leak when Thread is never + joined (GH-26103) (GH-26142) + +When a Thread is not joined after it has stopped, its lock may remain in the _shutdown_locks set until interpreter shutdown. If many threads are created this way, the _shutdown_locks set could therefore grow endlessly. To avoid such a situation, purge expired locks each time a new one is added or removed.. +(cherry picked from commit c10c2ec7a0e06975e8010c56c9c3270f8ea322ec) + +Co-authored-by: Antoine Pitrou + +Automerge-Triggered-By: GH:pitrou +--- + Lib/test/test_threading.py | 8 ++++++++ + Lib/threading.py | 19 ++++++++++++++++++- + .../2021-05-13-19-07-28.bpo-37788.adeFcf.rst | 1 + + 3 files changed, 27 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Library/2021-05-13-19-07-28.bpo-37788.adeFcf.rst + +diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py +index c21cdf8eb7be9c..67e061e8aa63bc 100644 +--- a/Lib/test/test_threading.py ++++ b/Lib/test/test_threading.py +@@ -805,6 +805,14 @@ def __del__(self): + """) + self.assertEqual(out.rstrip(), b"thread_dict.atexit = 'value'") + ++ def test_leak_without_join(self): ++ # bpo-37788: Test that a thread which is not joined explicitly ++ # does not leak. Test written for reference leak checks. ++ def noop(): pass ++ with support.wait_threads_exit(): ++ threading.Thread(target=noop).start() ++ # Thread.join() is not called ++ + + class ThreadJoinOnShutdown(BaseTestCase): + +diff --git a/Lib/threading.py b/Lib/threading.py +index 4da5c657b1b73a..702acaa0054307 100644 +--- a/Lib/threading.py ++++ b/Lib/threading.py +@@ -755,12 +755,27 @@ def _newname(template="Thread-%d"): + _active = {} # maps thread id to Thread object + _limbo = {} + _dangling = WeakSet() ++ + # Set of Thread._tstate_lock locks of non-daemon threads used by _shutdown() + # to wait until all Python thread states get deleted: + # see Thread._set_tstate_lock(). + _shutdown_locks_lock = _allocate_lock() + _shutdown_locks = set() + ++def _maintain_shutdown_locks(): ++ """ ++ Drop any shutdown locks that don't correspond to running threads anymore. ++ ++ Calling this from time to time avoids an ever-growing _shutdown_locks ++ set when Thread objects are not joined explicitly. See bpo-37788. ++ ++ This must be called with _shutdown_locks_lock acquired. ++ """ ++ # If a lock was released, the corresponding thread has exited ++ to_remove = [lock for lock in _shutdown_locks if not lock.locked()] ++ _shutdown_locks.difference_update(to_remove) ++ ++ + # Main class for threads + + class Thread: +@@ -932,6 +947,7 @@ def _set_tstate_lock(self): + + if not self.daemon: + with _shutdown_locks_lock: ++ _maintain_shutdown_locks() + _shutdown_locks.add(self._tstate_lock) + + def _bootstrap_inner(self): +@@ -987,7 +1003,8 @@ def _stop(self): + self._tstate_lock = None + if not self.daemon: + with _shutdown_locks_lock: +- _shutdown_locks.discard(lock) ++ # Remove our lock and other released locks from _shutdown_locks ++ _maintain_shutdown_locks() + + def _delete(self): + "Remove current thread from the dict of currently running threads." +diff --git a/Misc/NEWS.d/next/Library/2021-05-13-19-07-28.bpo-37788.adeFcf.rst b/Misc/NEWS.d/next/Library/2021-05-13-19-07-28.bpo-37788.adeFcf.rst +new file mode 100644 +index 00000000000000..0c33923e992452 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2021-05-13-19-07-28.bpo-37788.adeFcf.rst +@@ -0,0 +1 @@ ++Fix a reference leak when a Thread object is never joined. diff --git a/python-385 b/python-385 deleted file mode 100644 index 9824719704d771d08545ad532c66a0977ed22dfc..0000000000000000000000000000000000000000 --- a/python-385 +++ /dev/null @@ -1,1955 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Download Python | Python.org - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-

Notice: While Javascript is not essential for this website, your interaction with the content will be limited. Please turn Javascript on for the full experience.

-
- - - - -
- - - -
- - - - -
- -
- -
- - - - - - - -
- - -

Active Python Releases

-

For more information visit the Python Developer's Guide.

- -
- Python version - Maintenance status - First released - End of support - Release schedule -
- -
- - -
- -

Looking for a specific release?

-

Python releases by version number:

- -
- Release version - Release date -   - Click for more -
- -

View older releases

- -
- - -
- -
-

Licenses

-

All Python releases are Open Source. Historically, most, but not all, Python releases have also been GPL-compatible. The Licenses page details GPL-compatibility and Terms and Conditions.

-

Read more

- -
- -
-

Sources

-

For most Unix systems, you must download and compile the source code. The same source code archive can also be used to build the Windows and Mac versions, and is the starting point for ports to all other platforms.

- -

Download the latest Python 3 and Python 2 source.

- -

Read more

- -
- -
-

Alternative Implementations

-

This site hosts the "traditional" implementation of Python (nicknamed CPython). A number of alternative implementations are available as well.

-

Read more

- -
- -
-

History

-

Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum in the Netherlands as a successor of a language called ABC. Guido remains Python’s principal author, although it includes many contributions from others.

-

Read more

- -
- -
- - - -
-

Information about specific ports, and developer info

- - -
- -
-

OpenPGP Public Keys

-

-Source and binary executables are signed by the release manager or binary builder using their -OpenPGP key. Release files for currently supported releases are signed by the following: -

- -
-

-Release files for older releases which have now reached end-of-life may have been signed by one of the following: -

- -
-

You can import a person's public keys from a public keyserver network server -you trust by running a command like:

- -
-gpg --recv-keys [key id]
-
- -

-or, in many cases, public keys can also be found -at keybase.io. -On the version-specific download pages, you should see a link to both the -downloadable file and a detached signature file. To verify the authenticity -of the download, grab both files and then run this command:

- -
-gpg --verify Python-3.6.2.tgz.asc
-
- -

Note that you must use the name of the signature file, and you should use the -one that's appropriate to the download you're verifying.

- -
    -
  • (These instructions are geared to -GnuPG and Unix command-line users.) -
  • -
- - -

Other Useful Items

-
    -
  • Looking for 3rd party Python modules? The -Package Index has many of them.
  • -
  • You can view the standard documentation -online, or you can download it -in HTML, PostScript, PDF and other formats. See the main -Documentation page.
  • -
  • Information on tools for unpacking archive files -provided on python.org is available.
  • -
  • Tip: even if you download a ready-made binary for your -platform, it makes sense to also download the source. -This lets you browse the standard library (the subdirectory Lib) -and the standard collections of demos (Demo) and tools -(Tools) that come with it. There's a lot you can learn from the -source!
  • -
  • There is also a collection of Emacs packages -that the Emacsing Pythoneer might find useful. This includes major -modes for editing Python, C, C++, Java, etc., Python debugger -interfaces and more. Most packages are compatible with Emacs and -XEmacs.
  • -
- -

Want to contribute?

- -

Want to contribute? See the Python Developer's Guide -to learn about how Python development is managed.

-
-
- - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/python3.spec b/python3.spec index bba1401a2701c28d59d3212edc926e18ea71c213..cd36a6f52e8e91cc0c21eee8800518228cb1f048 100644 --- a/python3.spec +++ b/python3.spec @@ -2,8 +2,8 @@ Name: python3 Summary: Interpreter of the Python3 programming language URL: https://www.python.org/ -Version: 3.8.5 -Release: 7 +Version: 3.8.8 +Release: 1 License: Python %global branchversion 3.8 @@ -95,9 +95,6 @@ Patch178: 00178-dont-duplicate-flags-in-sysconfig.patch Patch189: 00189-use-rpm-wheels.patch Patch205: 00205-make-libpl-respect-lib64.patch Patch251: 00251-change-user-install-location.patch -Patch252: CVE-2020-27619.patch -Patch254: CVE-2021-3177.patch -Patch255: backport-CVE-2021-23336.patch Provides: python%{branchversion} = %{version}-%{release} Provides: python(abi) = %{branchversion} @@ -190,9 +187,6 @@ rm -r Modules/expat rm Lib/ensurepip/_bundled/*.whl %patch205 -p1 %patch251 -p1 -%patch252 -p1 -%patch254 -p1 -%patch255 -p1 rm configure pyconfig.h.in @@ -800,6 +794,12 @@ export BEP_GTDLIST="$BEP_GTDLIST_TMP" %{_mandir}/*/* %changelog +* Mon Mar 29 2021 shixuantong - 3.8.8-1 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:upgrade version to 3.8.8 + * Web Mar 03 2021 wuchaochao - 3.8.5-7 - Type:cves - ID:CVE-2021-23336