diff --git a/backport-bpo-36253-Remove-use-after-free-reference-in-ctypes-.patch b/backport-bpo-36253-Remove-use-after-free-reference-in-ctypes-.patch new file mode 100644 index 0000000000000000000000000000000000000000..62975bb19655e9bec3b556067ed31c8b2fb9efc3 --- /dev/null +++ b/backport-bpo-36253-Remove-use-after-free-reference-in-ctypes-.patch @@ -0,0 +1,28 @@ +From a9b6033179b64b985394ad351501089a6a94fc9d Mon Sep 17 00:00:00 2001 +From: Ben Harper +Date: Tue, 10 Sep 2019 11:20:15 -0400 +Subject: [PATCH] bpo-36253: Remove use after free reference in ctypes test + suite (GH-12257) + +--- + Lib/ctypes/test/test_stringptr.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Lib/ctypes/test/test_stringptr.py b/Lib/ctypes/test/test_stringptr.py +index 95cd161..c20951f 100644 +--- a/Lib/ctypes/test/test_stringptr.py ++++ b/Lib/ctypes/test/test_stringptr.py +@@ -70,8 +70,8 @@ def test_functions(self): + x = r[0], r[1], r[2], r[3], r[4] + self.assertEqual(x, (b"c", b"d", b"e", b"f", b"\000")) + del buf +- # x1 will NOT be the same as x, usually: +- x1 = r[0], r[1], r[2], r[3], r[4] ++ # Because r is a pointer to memory that is freed after deleting buf, ++ # the pointer is hanging and using it would reference freed memory. + + if __name__ == '__main__': + unittest.main() +-- +1.8.3.1 + diff --git a/backport-bpo-36333-bpo-36356-Fix-_PyEval_FiniThreads-GH-12432.patch b/backport-bpo-36333-bpo-36356-Fix-_PyEval_FiniThreads-GH-12432.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec7b81938490c0b3e7b1be5a61bdc6626096fc4a --- /dev/null +++ b/backport-bpo-36333-bpo-36356-Fix-_PyEval_FiniThreads-GH-12432.patch @@ -0,0 +1,47 @@ +From a712679a2bffffefaacdc05f788d6ea50f72a561 Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Tue, 19 Mar 2019 14:19:38 +0100 +Subject: [PATCH] bpo-36333, bpo-36356: Fix _PyEval_FiniThreads() (GH-12432) + +_PyEval_FiniThreads() now free the pending lock. +--- + Python/ceval.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/Python/ceval.c b/Python/ceval.c +index 634edba..38c6f2f 100644 +--- a/Python/ceval.c ++++ b/Python/ceval.c +@@ -154,8 +154,9 @@ PyEval_ThreadsInitialized(void) + void + PyEval_InitThreads(void) + { +- if (gil_created()) ++ if (gil_created()) { + return; ++ } + create_gil(); + take_gil(PyThreadState_GET()); + _PyRuntime.ceval.pending.main_thread = PyThread_get_thread_ident(); +@@ -166,10 +167,17 @@ PyEval_InitThreads(void) + void + _PyEval_FiniThreads(void) + { +- if (!gil_created()) ++ if (!gil_created()) { + return; ++ } ++ + destroy_gil(); + assert(!gil_created()); ++ ++ if (_PyRuntime.ceval.pending.lock != NULL) { ++ PyThread_free_lock(_PyRuntime.ceval.pending.lock); ++ _PyRuntime.ceval.pending.lock = NULL; ++ } + } + + void +-- +1.8.3.1 + diff --git a/backport-bpo-36356-Fix-memory-leak-in-_asynciomodule.c-GH-165.patch b/backport-bpo-36356-Fix-memory-leak-in-_asynciomodule.c-GH-165.patch new file mode 100644 index 0000000000000000000000000000000000000000..a7f57458e692e30588570e354c786fde87b1d0a2 --- /dev/null +++ b/backport-bpo-36356-Fix-memory-leak-in-_asynciomodule.c-GH-165.patch @@ -0,0 +1,41 @@ +From 13915a3100608f011b29da2f3716c990f523b631 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Mon, 7 Oct 2019 09:38:00 -0700 +Subject: [PATCH] bpo-36356: Fix memory leak in _asynciomodule.c (GH-16598) + +(cherry picked from commit 321def805abc5b7c92c7e90ca90cb2434fdab855) + +Co-authored-by: Ben Harper +--- + Modules/_asynciomodule.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c +index 7880de3..b1cd5b1 100644 +--- a/Modules/_asynciomodule.c ++++ b/Modules/_asynciomodule.c +@@ -33,6 +33,7 @@ static PyObject *asyncio_task_repr_info_func; + static PyObject *asyncio_InvalidStateError; + static PyObject *asyncio_CancelledError; + static PyObject *context_kwname; ++static int module_initialized; + + static PyObject *cached_running_holder; + static volatile uint64_t cached_running_holder_tsid; +@@ -3243,6 +3244,12 @@ module_init(void) + if (asyncio_mod == NULL) { + goto fail; + } ++ if (module_initialized != 0) { ++ return 0; ++ } ++ else { ++ module_initialized = 1; ++ } + + current_tasks = PyDict_New(); + if (current_tasks == NULL) { +-- +1.8.3.1 + diff --git a/backport-bpo-37169-Rewrite-_PyObject_IsFreed-unit-tests-GH-13.patch b/backport-bpo-37169-Rewrite-_PyObject_IsFreed-unit-tests-GH-13.patch new file mode 100644 index 0000000000000000000000000000000000000000..f24c81d6ae2add8448f4e15bba0cbdd263dc82b8 --- /dev/null +++ b/backport-bpo-37169-Rewrite-_PyObject_IsFreed-unit-tests-GH-13.patch @@ -0,0 +1,152 @@ +From 3bf0f3ad2046ac674d8e8a2c074a5a8b3327797d Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Fri, 7 Jun 2019 16:22:21 +0200 +Subject: [PATCH] bpo-37169: Rewrite _PyObject_IsFreed() unit tests (GH-13888) + +Replace two Python function calls with a single one to ensure that no +memory allocation is done between the invalid object is created and +when _PyObject_IsFreed() is called. +--- + Lib/test/test_capi.py | 29 +++++++++++----------- + .../Tests/2019-06-07-12-23-15.bpo-37169.yfXTFg.rst | 1 + + Modules/_testcapimodule.c | 27 ++++++++++---------- + 3 files changed, 30 insertions(+), 27 deletions(-) + create mode 100644 Misc/NEWS.d/next/Tests/2019-06-07-12-23-15.bpo-37169.yfXTFg.rst + +diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py +index 3ed2263..b0f1416 100644 +--- a/Lib/test/test_capi.py ++++ b/Lib/test/test_capi.py +@@ -522,28 +522,29 @@ class PyMemDebugTests(unittest.TestCase): + code = 'import _testcapi; _testcapi.pyobject_malloc_without_gil()' + self.check_malloc_without_gil(code) + +- def check_pyobject_is_freed(self, func): +- code = textwrap.dedent(''' ++ def check_pyobject_is_freed(self, func_name): ++ code = textwrap.dedent(f''' + import gc, os, sys, _testcapi + # Disable the GC to avoid crash on GC collection + gc.disable() +- obj = _testcapi.{func}() +- error = (_testcapi.pyobject_is_freed(obj) == False) +- # Exit immediately to avoid a crash while deallocating +- # the invalid object +- os._exit(int(error)) ++ try: ++ _testcapi.{func_name}() ++ # Exit immediately to avoid a crash while deallocating ++ # the invalid object ++ os._exit(0) ++ except _testcapi.error: ++ os._exit(1) + ''') +- code = code.format(func=func) + assert_python_ok('-c', code, PYTHONMALLOC=self.PYTHONMALLOC) + +- def test_pyobject_is_freed_uninitialized(self): +- self.check_pyobject_is_freed('pyobject_uninitialized') ++ def test_pyobject_uninitialized_is_freed(self): ++ self.check_pyobject_is_freed('check_pyobject_uninitialized_is_freed') + +- def test_pyobject_is_freed_forbidden_bytes(self): +- self.check_pyobject_is_freed('pyobject_forbidden_bytes') ++ def test_pyobject_forbidden_bytes_is_freed(self): ++ self.check_pyobject_is_freed('check_pyobject_forbidden_bytes_is_freed') + +- def test_pyobject_is_freed_free(self): +- self.check_pyobject_is_freed('pyobject_freed') ++ def test_pyobject_freed_is_freed(self): ++ self.check_pyobject_is_freed('check_pyobject_freed_is_freed') + + + class PyMemMallocDebugTests(PyMemDebugTests): +diff --git a/Misc/NEWS.d/next/Tests/2019-06-07-12-23-15.bpo-37169.yfXTFg.rst b/Misc/NEWS.d/next/Tests/2019-06-07-12-23-15.bpo-37169.yfXTFg.rst +new file mode 100644 +index 0000000..f2f0a8b +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2019-06-07-12-23-15.bpo-37169.yfXTFg.rst +@@ -0,0 +1 @@ ++Rewrite ``_PyObject_IsFreed()`` unit tests. +diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c +index 6996d22..55cfdb8 100644 +--- a/Modules/_testcapimodule.c ++++ b/Modules/_testcapimodule.c +@@ -4248,15 +4248,17 @@ test_pymem_getallocatorsname(PyObject *self, PyObject *args) + + + static PyObject* +-pyobject_is_freed(PyObject *self, PyObject *op) ++test_pyobject_is_freed(const char *test_name, PyObject *op) + { +- int res = _PyObject_IsFreed(op); +- return PyBool_FromLong(res); ++ if (!_PyObject_IsFreed(op)) { ++ return raiseTestError(test_name, "object is not seen as freed"); ++ } ++ Py_RETURN_NONE; + } + + + static PyObject* +-pyobject_uninitialized(PyObject *self, PyObject *args) ++check_pyobject_uninitialized_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) + { + PyObject *op = (PyObject *)PyObject_Malloc(sizeof(PyObject)); + if (op == NULL) { +@@ -4265,12 +4267,12 @@ pyobject_uninitialized(PyObject *self, PyObject *args) + /* Initialize reference count to avoid early crash in ceval or GC */ + Py_REFCNT(op) = 1; + /* object fields like ob_type are uninitialized! */ +- return op; ++ return test_pyobject_is_freed("check_pyobject_uninitialized_is_freed", op); + } + + + static PyObject* +-pyobject_forbidden_bytes(PyObject *self, PyObject *args) ++check_pyobject_forbidden_bytes_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) + { + /* Allocate an incomplete PyObject structure: truncate 'ob_type' field */ + PyObject *op = (PyObject *)PyObject_Malloc(offsetof(PyObject, ob_type)); +@@ -4281,12 +4283,12 @@ pyobject_forbidden_bytes(PyObject *self, PyObject *args) + Py_REFCNT(op) = 1; + /* ob_type field is after the memory block: part of "forbidden bytes" + when using debug hooks on memory allocatrs! */ +- return op; ++ return test_pyobject_is_freed("check_pyobject_forbidden_bytes_is_freed", op); + } + + + static PyObject* +-pyobject_freed(PyObject *self, PyObject *args) ++check_pyobject_freed_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) + { + PyObject *op = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type); + if (op == NULL) { +@@ -4296,7 +4298,7 @@ pyobject_freed(PyObject *self, PyObject *args) + /* Reset reference count to avoid early crash in ceval or GC */ + Py_REFCNT(op) = 1; + /* object memory is freed! */ +- return op; ++ return test_pyobject_is_freed("check_pyobject_freed_is_freed", op); + } + + +@@ -4876,10 +4878,9 @@ static PyMethodDef TestMethods[] = { + {"pymem_api_misuse", pymem_api_misuse, METH_NOARGS}, + {"pymem_malloc_without_gil", pymem_malloc_without_gil, METH_NOARGS}, + {"pymem_getallocatorsname", test_pymem_getallocatorsname, METH_NOARGS}, +- {"pyobject_is_freed", (PyCFunction)(void(*)(void))pyobject_is_freed, METH_O}, +- {"pyobject_uninitialized", pyobject_uninitialized, METH_NOARGS}, +- {"pyobject_forbidden_bytes", pyobject_forbidden_bytes, METH_NOARGS}, +- {"pyobject_freed", pyobject_freed, METH_NOARGS}, ++ {"check_pyobject_uninitialized_is_freed", check_pyobject_uninitialized_is_freed, METH_NOARGS}, ++ {"check_pyobject_forbidden_bytes_is_freed", check_pyobject_forbidden_bytes_is_freed, METH_NOARGS}, ++ {"check_pyobject_freed_is_freed", check_pyobject_freed_is_freed, METH_NOARGS}, + {"pyobject_malloc_without_gil", pyobject_malloc_without_gil, METH_NOARGS}, + {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, + {"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS}, +-- +1.8.3.1 + diff --git a/backport-bpo-44363-Get-test_capi-passing-with-address-sanitiz.patch b/backport-bpo-44363-Get-test_capi-passing-with-address-sanitiz.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d682d63bc72633f823be10c79e3d7e2e78acd05 --- /dev/null +++ b/backport-bpo-44363-Get-test_capi-passing-with-address-sanitiz.patch @@ -0,0 +1,75 @@ +From 31aa0dbff4c1d39c9d77c6c8f4a61d0e46c1268b Mon Sep 17 00:00:00 2001 +From: Mark Shannon +Date: Thu, 10 Jun 2021 12:37:22 +0100 +Subject: [PATCH] bpo-44363: Get test_capi passing with address sanitizer + (GH-26639) + +--- + Include/Python.h | 11 ++++++++++- + .../next/Tests/2021-06-10-11-19-43.bpo-44363.-K9jD0.rst | 2 ++ + Modules/_testcapimodule.c | 5 +++++ + 3 files changed, 17 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Tests/2021-06-10-11-19-43.bpo-44363.-K9jD0.rst + +diff --git a/Include/Python.h b/Include/Python.h +index 54ea321..2ebddb9 100644 +--- a/Include/Python.h ++++ b/Include/Python.h +@@ -63,13 +63,22 @@ + #include "pyport.h" + #include "pymacro.h" + +-/* A convenient way for code to know if clang's memory sanitizer is enabled. */ ++/* A convenient way for code to know if sanitizers are enabled. */ + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + # if !defined(_Py_MEMORY_SANITIZER) + # define _Py_MEMORY_SANITIZER + # endif + # endif ++# if __has_feature(address_sanitizer) ++# if !defined(_Py_ADDRESS_SANITIZER) ++# define _Py_ADDRESS_SANITIZER ++# endif ++# endif ++#elif defined(__GNUC__) ++# if defined(__SANITIZE_ADDRESS__) ++# define _Py_ADDRESS_SANITIZER ++# endif + #endif + + #include "pyatomic.h" +diff --git a/Misc/NEWS.d/next/Tests/2021-06-10-11-19-43.bpo-44363.-K9jD0.rst b/Misc/NEWS.d/next/Tests/2021-06-10-11-19-43.bpo-44363.-K9jD0.rst +new file mode 100644 +index 0000000..28468cb +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2021-06-10-11-19-43.bpo-44363.-K9jD0.rst +@@ -0,0 +1,2 @@ ++Account for address sanitizer in test_capi. test_capi now passes when run ++GCC address sanitizer. +diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c +index 55cfdb8..a43143a 100644 +--- a/Modules/_testcapimodule.c ++++ b/Modules/_testcapimodule.c +@@ -4290,6 +4290,10 @@ check_pyobject_forbidden_bytes_is_freed(PyObject *self, PyObject *Py_UNUSED(args + static PyObject* + check_pyobject_freed_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) + { ++ /* This test would fail if run with the address sanitizer */ ++#ifdef _Py_ADDRESS_SANITIZER ++ Py_RETURN_NONE; ++#else + PyObject *op = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type); + if (op == NULL) { + return NULL; +@@ -4299,6 +4303,7 @@ check_pyobject_freed_is_freed(PyObject *self, PyObject *Py_UNUSED(args)) + Py_REFCNT(op) = 1; + /* object memory is freed! */ + return test_pyobject_is_freed("check_pyobject_freed_is_freed", op); ++#endif + } + + +-- +1.8.3.1 + diff --git a/python3.spec b/python3.spec index 6234d146c3181fcd77b7910d17bbee3028d05baf..0d9c900931efa8e9ef0cfe88a30117a9a5525794 100644 --- a/python3.spec +++ b/python3.spec @@ -3,7 +3,7 @@ Summary: Interpreter of the Python3 programming language URL: https://www.python.org/ Version: 3.7.9 -Release: 15 +Release: 16 License: Python %global branchversion 3.7 @@ -145,6 +145,12 @@ Patch6034: backport-42146-Unify-cleanup-in-subprocess_fork_exec-GH-2.patch Patch6035: backport-CVE-2021-3426.patch Patch6036: backport-37193-Remove-thread-objects-which-finished-proce.patch +Patch6037: backport-bpo-36333-bpo-36356-Fix-_PyEval_FiniThreads-GH-12432.patch +Patch6038: backport-bpo-37169-Rewrite-_PyObject_IsFreed-unit-tests-GH-13.patch +Patch6039: backport-bpo-44363-Get-test_capi-passing-with-address-sanitiz.patch +Patch6040: backport-bpo-36253-Remove-use-after-free-reference-in-ctypes-.patch +Patch6041: backport-bpo-36356-Fix-memory-leak-in-_asynciomodule.c-GH-165.patch + Recommends: %{name}-help = %{version}-%{release} Provides: python%{branchversion} = %{version}-%{release} Provides: python(abi) = %{branchversion} @@ -272,6 +278,11 @@ rm Lib/ensurepip/_bundled/*.whl %patch6034 -p1 %patch6035 -p1 %patch6036 -p1 +%patch6037 -p1 +%patch6038 -p1 +%patch6039 -p1 +%patch6040 -p1 +%patch6041 -p1 sed -i "s/generic_os/%{_vendor}/g" Lib/platform.py rm configure pyconfig.h.in @@ -873,6 +884,16 @@ export BEP_GTDLIST="$BEP_GTDLIST_TMP" %{_mandir}/*/* %changelog +* Fri Sep 17 2021 shixuantong - 3.7.9-15 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:Remove use after free reference in ctypes test suite + Fix _PyEval_FiniThreads() + Fix memory leak in _asynciomodule.c + Rewrite _PyObject_IsFreed() unit tests + Get test_capi passing with address sanitizer + * Thu Jul 29 2021 hehuazhen - 3.7.9-15 - Type:bugfix - ID:NA