Fix locking in cert_store_stats and get_ca_certs

Fix xml tree assert error
Update openssl version for test case
This commit is contained in:
xinsheng3 2024-07-10 11:11:27 +08:00
parent 90d2230471
commit 38559af9fc
4 changed files with 307 additions and 1 deletions

View File

@ -0,0 +1,177 @@
From b228655c227b2ca298a8ffac44d14ce3d22f6faa Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Fri, 10 May 2024 06:46:12 -0500
Subject: [PATCH] [3.9] gh-114572: Fix locking in cert_store_stats and
get_ca_certs (#118109)
---
...-04-19-11-21-13.gh-issue-114572.t1QMQD.rst | 4 +
Modules/_ssl.c | 91 ++++++++++++++++++-
2 files changed, 92 insertions(+), 3 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2024-04-19-11-21-13.gh-issue-114572.t1QMQD.rst
diff --git a/Misc/NEWS.d/next/Security/2024-04-19-11-21-13.gh-issue-114572.t1QMQD.rst b/Misc/NEWS.d/next/Security/2024-04-19-11-21-13.gh-issue-114572.t1QMQD.rst
new file mode 100644
index 0000000000..b4f9fe64db
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2024-04-19-11-21-13.gh-issue-114572.t1QMQD.rst
@@ -0,0 +1,4 @@
+:meth:`ssl.SSLContext.cert_store_stats` and
+:meth:`ssl.SSLContext.get_ca_certs` now correctly lock access to the
+certificate store, when the :class:`ssl.SSLContext` is shared across
+multiple threads.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 3f95d3e103..5e0be34d6f 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -166,6 +166,10 @@ extern const SSL_METHOD *TLSv1_2_method(void);
# define PY_OPENSSL_1_1_API 1
#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x30300000L) && !defined(LIBRESSL_VERSION_NUMBER)
+# define OPENSSL_VERSION_3_3 1
+#endif
+
/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f
* This includes the SSL_set_SSL_CTX() function.
*/
@@ -210,6 +214,16 @@ extern const SSL_METHOD *TLSv1_2_method(void);
#define HAVE_OPENSSL_CRYPTO_LOCK
#endif
+/* OpenSSL 1.1+ allows locking X509_STORE, 1.0.2 doesn't. */
+#ifdef OPENSSL_VERSION_1_1
+#define HAVE_OPENSSL_X509_STORE_LOCK
+#endif
+
+/* OpenSSL 3.3 added the X509_STORE_get1_objects API */
+#ifdef OPENSSL_VERSION_3_3
+#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1
+#endif
+
#if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2)
#define OPENSSL_NO_SSL2
#endif
@@ -4675,6 +4689,54 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c)
#endif
}
+/* Shim of X509_STORE_get1_objects API from OpenSSL 3.3
+ * Only available with the X509_STORE_lock() API */
+#if defined(HAVE_OPENSSL_X509_STORE_LOCK) && !defined(OPENSSL_VERSION_3_3)
+#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1
+
+static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj)
+{
+ int ok;
+ X509_OBJECT *ret = X509_OBJECT_new();
+ if (ret == NULL) {
+ return NULL;
+ }
+ switch (X509_OBJECT_get_type(obj)) {
+ case X509_LU_X509:
+ ok = X509_OBJECT_set1_X509(ret, X509_OBJECT_get0_X509(obj));
+ break;
+ case X509_LU_CRL:
+ /* X509_OBJECT_get0_X509_CRL was not const-correct prior to 3.0.*/
+ ok = X509_OBJECT_set1_X509_CRL(
+ ret, X509_OBJECT_get0_X509_CRL((X509_OBJECT *)obj));
+ break;
+ default:
+ /* We cannot duplicate unrecognized types in a polyfill, but it is
+ * safe to leave an empty object. The caller will ignore it. */
+ ok = 1;
+ break;
+ }
+ if (!ok) {
+ X509_OBJECT_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+static STACK_OF(X509_OBJECT) *
+X509_STORE_get1_objects(X509_STORE *store)
+{
+ STACK_OF(X509_OBJECT) *ret;
+ if (!X509_STORE_lock(store)) {
+ return NULL;
+ }
+ ret = sk_X509_OBJECT_deep_copy(X509_STORE_get0_objects(store),
+ x509_object_dup, X509_OBJECT_free);
+ X509_STORE_unlock(store);
+ return ret;
+}
+#endif
+
PyDoc_STRVAR(PySSLContext_sni_callback_doc,
"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\
\n\
@@ -4704,7 +4766,15 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
int x509 = 0, crl = 0, ca = 0, i;
store = SSL_CTX_get_cert_store(self->ctx);
+#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
+ objs = X509_STORE_get1_objects(store);
+ if (objs == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
+ return NULL;
+ }
+#else
objs = X509_STORE_get0_objects(store);
+#endif
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
obj = sk_X509_OBJECT_value(objs, i);
switch (X509_OBJECT_get_type(obj)) {
@@ -4718,12 +4788,13 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
crl++;
break;
default:
- /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
- * As far as I can tell they are internal states and never
- * stored in a cert store */
+ /* Ignore unrecognized types. */
break;
}
}
+#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
+ sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
+#endif
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
"x509_ca", ca);
}
@@ -4755,7 +4826,15 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
}
store = SSL_CTX_get_cert_store(self->ctx);
+#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
+ objs = X509_STORE_get1_objects(store);
+ if (objs == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
+ return NULL;
+ }
+#else
objs = X509_STORE_get0_objects(store);
+#endif
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
X509_OBJECT *obj;
X509 *cert;
@@ -4783,9 +4862,15 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
}
Py_CLEAR(ci);
}
+#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
+ sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
+#endif
return rlist;
error:
+#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
+ sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
+#endif
Py_XDECREF(ci);
Py_XDECREF(rlist);
return NULL;
--
2.21.0.windows.1

View File

@ -0,0 +1,89 @@
From 4a08e7b3431cd32a0daf22a33421cd3035343dc4 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Sun, 11 Feb 2024 12:08:39 +0200
Subject: [PATCH] gh-115133: Fix tests for XMLPullParser with Expat 2.6.0
(GH-115164)
Feeding the parser by too small chunks defers parsing to prevent
CVE-2023-52425. Future versions of Expat may be more reactive.
Other adaptation:
For the expat version number, whether a feature exists in the header file is used to determine whether to execute a test case.
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 142ce2c..a8d5c2d 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -14,6 +14,8 @@ import locale
import operator
import os
import pickle
+import pyexpat
+import subprocess
import sys
import textwrap
import types
@@ -96,6 +98,11 @@ ENTITY_XML = """\
<document>&entity;</document>
"""
+macro_to_find = 'XML_SetReparseDeferralEnabled'
+header_file = '/usr/include/expat.h'
+result = subprocess.run(['grep', '-q', macro_to_find, header_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+fails_with_expat = (unittest.expectedFailure if result.returncode == 0 else lambda test: test)
+
EXTERNAL_ENTITY_XML = """\
<!DOCTYPE points [
<!ENTITY entity SYSTEM "file:///non-existing-file.xml">
@@ -1410,27 +1417,38 @@ class XMLPullParserTest(unittest.TestCase):
with self.assertRaises(StopIteration):
next(it)
- def test_simple_xml_with_ns(self):
+ def test_simple_xml(self, chunk_size=None):
parser = ET.XMLPullParser()
self.assert_event_tags(parser, [])
- self._feed(parser, "<!-- comment -->\n")
- self.assert_event_tags(parser, [])
- self._feed(parser, "<root xmlns='namespace'>\n")
+ self._feed(parser, "<!-- comment -->\n", chunk_size)
self.assert_event_tags(parser, [])
- self._feed(parser, "<element key='value'>text</element")
+ self._feed(parser,
+ "<root>\n <element key='value'>text</element",
+ chunk_size)
self.assert_event_tags(parser, [])
- self._feed(parser, ">\n")
- self.assert_event_tags(parser, [('end', '{namespace}element')])
- self._feed(parser, "<element>text</element>tail\n")
- self._feed(parser, "<empty-element/>\n")
+ self._feed(parser, ">\n", chunk_size)
+ self.assert_event_tags(parser, [('end', 'element')])
+ self._feed(parser, "<element>text</element>tail\n", chunk_size)
+ self._feed(parser, "<empty-element/>\n", chunk_size)
self.assert_event_tags(parser, [
- ('end', '{namespace}element'),
- ('end', '{namespace}empty-element'),
+ ('end', 'element'),
+ ('end', 'empty-element'),
])
- self._feed(parser, "</root>\n")
- self.assert_event_tags(parser, [('end', '{namespace}root')])
+ self._feed(parser, "</root>\n", chunk_size)
+ self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())
+ @fails_with_expat
+ def test_simple_xml_chunk_1(self):
+ self.test_simple_xml(chunk_size=1)
+
+ @fails_with_expat
+ def test_simple_xml_chunk_5(self):
+ self.test_simple_xml(chunk_size=5)
+
+ def test_simple_xml_chunk_22(self):
+ self.test_simple_xml(chunk_size=22)
+
def test_ns_events(self):
parser = ET.XMLPullParser(events=('start-ns', 'end-ns'))
self._feed(parser, "<!-- comment -->\n")

View File

@ -3,7 +3,7 @@ Summary: Interpreter of the Python3 programming language
URL: https://www.python.org/
Version: 3.9.9
Release: 28
Release: 29
License: Python-2.0
%global branchversion 3.9
@ -109,6 +109,9 @@ Patch6015: backport-CVE-2007-4559.patch
Patch6016: backport-CVE-2023-40217.patch
Patch6017: backport-3.9-gh-104049-do-not-expose-on-disk-location-from-Si.patch
Patch6018: backport-3.9-gh-99889-Fix-directory-traversal-security-flaw-i.patch
Patch6019: backport-3.9-gh-114572-Fix-locking-in-cert_store_stats-and-ge.patch
Patch6020: backport-fix_xml_tree_assert_error.patch
Patch6021: update-openssl-version-for-test-case.patch
Patch9000: add-the-sm3-method-for-obtaining-the-salt-value.patch
Patch9001: python3-Add-sw64-architecture.patch
@ -216,6 +219,9 @@ rm -r Modules/expat
%patch6016 -p1
%patch6017 -p1
%patch6018 -p1
%patch6019 -p1
%patch6020 -p1
%patch6021 -p1
%patch9000 -p1
%patch9001 -p1
@ -843,6 +849,15 @@ export BEP_GTDLIST="$BEP_GTDLIST_TMP"
%{_mandir}/*/*
%changelog
* Web Jul 10 2024 xinsheng <xinsheng3@huawei.com> - 3.9.9-29
- Type:bugfix
- CVE:NA
- SUG:NA
- DESC:backport upstream patches
- Fix locking in cert_store_stats and get_ca_certs
- Fix xml tree assert error
- Update openssl version for test case
* Wed Oct 25 zhuofeng <zhuofeng2@huawei.com> - 3.9.9-28
- Type:bugfix
- CVE:NA

View File

@ -0,0 +1,25 @@
From d7a637e43086c51d0e2b4cd2f9324f1c60eced50 Mon Sep 17 00:00:00 2001
From: xinsheng3 <xinsheng3@huawei.com>
Date: Thu, 20 Jun 2024 15:29:05 +0800
Subject: [PATCH] update openssl version for test case.patch
---
Lib/test/test_ssl.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 2c71c27..d95f0ef 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -589,7 +589,7 @@ class BasicSocketTests(unittest.TestCase):
self.assertGreaterEqual(fix, 0)
self.assertLess(fix, 256)
self.assertGreaterEqual(patch, 0)
- self.assertLessEqual(patch, 63)
+ self.assertLessEqual(patch, 128)
self.assertGreaterEqual(status, 0)
self.assertLessEqual(status, 15)
# Version string as returned by {Open,Libre}SSL, the format might change
--
2.33.0