mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-08-31 03:45:41 +00:00
python3-aiohttp: fix CVE-2026-54275
This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/aio-libs/aiohttp/commit/0ca2b6c28a25726527a8b60f25960262a91ed0e0 [2] https://github.com/advisories/GHSA-4m7w-qmgq-4wj5 Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
From 23328dc1950071dd1e05ac6aeb631874ef94afe3 Mon Sep 17 00:00:00 2001
|
||||
From: "J. Nick Koston" <nick@koston.org>
|
||||
Date: Sun, 7 Jun 2026 00:30:30 -0500
|
||||
Subject: [PATCH] [PR #12835/1e94b3e8 backport][3.14] Tls server hostname pool
|
||||
key (#12847)
|
||||
|
||||
CVE: CVE-2026-54275
|
||||
Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/0ca2b6c28a25726527a8b60f25960262a91ed0e0]
|
||||
|
||||
(cherry picked from commit 0ca2b6c28a25726527a8b60f25960262a91ed0e0)
|
||||
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
||||
---
|
||||
CHANGES/12835.bugfix.rst | 1 +
|
||||
aiohttp/client_reqrep.py | 2 ++
|
||||
tests/test_client_functional.py | 31 +++++++++++++++++++++++++++++++
|
||||
tests/test_client_request.py | 16 ++++++++++++++++
|
||||
4 files changed, 50 insertions(+)
|
||||
create mode 100644 CHANGES/12835.bugfix.rst
|
||||
|
||||
diff --git a/CHANGES/12835.bugfix.rst b/CHANGES/12835.bugfix.rst
|
||||
new file mode 100644
|
||||
index 000000000..84a8ae006
|
||||
--- /dev/null
|
||||
+++ b/CHANGES/12835.bugfix.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Included the per-request ``server_hostname`` override in the :class:`~aiohttp.TCPConnector` connection pool key, so a pooled TLS connection is no longer reused for a request that sets ``server_hostname`` to a different value -- by :user:`bdraco`.
|
||||
diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py
|
||||
index a9e079589..5fe83fa88 100644
|
||||
--- a/aiohttp/client_reqrep.py
|
||||
+++ b/aiohttp/client_reqrep.py
|
||||
@@ -255,6 +255,7 @@ class ConnectionKey(NamedTuple):
|
||||
proxy: Optional[URL]
|
||||
proxy_auth: Optional[BasicAuth]
|
||||
proxy_headers_hash: Optional[int] # hash(CIMultiDict)
|
||||
+ server_hostname: str | None = None
|
||||
|
||||
|
||||
def _is_expected_content_type(
|
||||
@@ -964,6 +965,7 @@ class ClientRequest:
|
||||
self.proxy,
|
||||
self.proxy_auth,
|
||||
h,
|
||||
+ self.server_hostname,
|
||||
),
|
||||
)
|
||||
|
||||
diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py
|
||||
index ea31567c4..60caf6e2a 100644
|
||||
--- a/tests/test_client_functional.py
|
||||
+++ b/tests/test_client_functional.py
|
||||
@@ -720,6 +720,37 @@ async def test_ssl_client(
|
||||
assert txt == "Test message"
|
||||
|
||||
|
||||
+async def test_server_hostname_override_not_reused(
|
||||
+ aiohttp_server: AiohttpServer,
|
||||
+) -> None:
|
||||
+ """A pooled TLS connection must not be reused for a different server_hostname."""
|
||||
+ trustme = pytest.importorskip("trustme")
|
||||
+
|
||||
+ ca = trustme.CA()
|
||||
+ cert = ca.issue_cert("first.example")
|
||||
+ server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
+ cert.configure_cert(server_ctx)
|
||||
+ client_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
|
||||
+ ca.configure_trust(client_ctx)
|
||||
+
|
||||
+ async def handler(request: web.Request) -> web.Response:
|
||||
+ return web.Response(text="ok")
|
||||
+
|
||||
+ app = web.Application()
|
||||
+ app.router.add_route("GET", "/", handler)
|
||||
+ server = await aiohttp_server(app, ssl=server_ctx)
|
||||
+ url = server.make_url("/")
|
||||
+
|
||||
+ connector = aiohttp.TCPConnector(ssl=client_ctx, limit=1, limit_per_host=1)
|
||||
+ async with aiohttp.ClientSession(connector=connector) as session:
|
||||
+ async with session.get(url, server_hostname="first.example") as resp:
|
||||
+ assert resp.status == 200
|
||||
+ await resp.read()
|
||||
+
|
||||
+ with pytest.raises(aiohttp.ClientConnectorCertificateError):
|
||||
+ await session.get(url, server_hostname="second.example")
|
||||
+
|
||||
+
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 11), reason="ssl_shutdown_timeout requires Python 3.11+"
|
||||
)
|
||||
diff --git a/tests/test_client_request.py b/tests/test_client_request.py
|
||||
index e3cdc1c62..4c91245a5 100644
|
||||
--- a/tests/test_client_request.py
|
||||
+++ b/tests/test_client_request.py
|
||||
@@ -1611,6 +1611,22 @@ async def test_connection_key_without_proxy() -> None:
|
||||
await req.close()
|
||||
|
||||
|
||||
+async def test_connection_key_includes_server_hostname(
|
||||
+ make_request: _RequestMaker,
|
||||
+) -> None:
|
||||
+ """A server_hostname override must be part of the connection reuse key."""
|
||||
+ url = URL("https://127.0.0.1:8443/")
|
||||
+ none_req = make_request("GET", url)
|
||||
+ first = make_request("GET", url, server_hostname="first.example")
|
||||
+ first_again = make_request("GET", url, server_hostname="first.example")
|
||||
+ second = make_request("GET", url, server_hostname="second.example")
|
||||
+
|
||||
+ assert first.connection_key.server_hostname == "first.example"
|
||||
+ assert first.connection_key != none_req.connection_key
|
||||
+ assert first.connection_key != second.connection_key
|
||||
+ assert first.connection_key == first_again.connection_key
|
||||
+
|
||||
+
|
||||
def test_request_info_back_compat() -> None:
|
||||
"""Test RequestInfo can be created without real_url."""
|
||||
url = URL("http://example.com")
|
||||
@@ -11,6 +11,7 @@ SRC_URI += " \
|
||||
file://CVE-2026-47265.patch \
|
||||
file://CVE-2026-50269.patch \
|
||||
file://CVE-2026-54274.patch \
|
||||
file://CVE-2026-54275.patch \
|
||||
"
|
||||
|
||||
CVE_PRODUCT = "aiohttp"
|
||||
|
||||
Reference in New Issue
Block a user