mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-09-11 19:30:14 +00:00
python3-aiohttp: fix CVE-2026-34513
This patch applies the reviewed upstream fix commits shown in [1] and [2]. The advisory identifying the fix is referenced in [3]. [1] https://github.com/aio-libs/aiohttp/commit/c4d77c3533122be353b8afca8e8675e3b4cbda98 [2] https://github.com/aio-libs/aiohttp/commit/8ab84c52fe58ef34794fa9b12f00b06e626adcc0 [3] https://nvd.nist.gov/vuln/detail/CVE-2026-34513 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,211 @@
|
||||
From d094b4d3ad66d824ebfc8900234dff7aaf4acec0 Mon Sep 17 00:00:00 2001
|
||||
From: Sam Bull <git@sambull.org>
|
||||
Date: Sun, 22 Feb 2026 12:58:22 +0000
|
||||
Subject: [PATCH] Bound DNS cache (#12106) (#12117)
|
||||
|
||||
---------
|
||||
|
||||
CVE: CVE-2026-34513
|
||||
Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/c4d77c3533122be353b8afca8e8675e3b4cbda98]
|
||||
|
||||
Backport Changes:
|
||||
- Imported OrderedDict for the aiohttp 3.9.5 collections layout.
|
||||
- Kept Dict[str, Any] because 3.9.5 lacks ResolveResult.
|
||||
- Removed ResolveResult annotations from the backported tests.
|
||||
- Kept family: int = 0 from the 3.9.5 connector API.
|
||||
- Kept _throttle_dns_events from the 3.9.5 DNS flow.
|
||||
|
||||
(cherry picked from commit 8ab84c52fe58ef34794fa9b12f00b06e626adcc0)
|
||||
Co-authored-by: gonas <nhjangh@gamil.com>
|
||||
(cherry picked from commit c4d77c3533122be353b8afca8e8675e3b4cbda98)
|
||||
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
||||
---
|
||||
CHANGES/12106.feature.rst | 1 +
|
||||
aiohttp/connector.py | 26 ++++++++++----
|
||||
tests/test_connector.py | 76 +++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 96 insertions(+), 7 deletions(-)
|
||||
create mode 100644 CHANGES/12106.feature.rst
|
||||
|
||||
diff --git a/CHANGES/12106.feature.rst b/CHANGES/12106.feature.rst
|
||||
new file mode 100644
|
||||
index 000000000..daa9088ee
|
||||
--- /dev/null
|
||||
+++ b/CHANGES/12106.feature.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Added a ``dns_cache_max_size`` parameter to ``TCPConnector`` to limit the size of the cache -- by :user:`Dreamsorcerer`.
|
||||
diff --git a/aiohttp/connector.py b/aiohttp/connector.py
|
||||
index f95ebe84c..7267d9a5c 100644
|
||||
--- a/aiohttp/connector.py
|
||||
+++ b/aiohttp/connector.py
|
||||
@@ -4,7 +4,7 @@ import random
|
||||
import sys
|
||||
import traceback
|
||||
import warnings
|
||||
-from collections import defaultdict, deque
|
||||
+from collections import OrderedDict, defaultdict, deque
|
||||
from contextlib import suppress
|
||||
from http import HTTPStatus
|
||||
from http.cookies import SimpleCookie
|
||||
@@ -690,25 +690,33 @@ class BaseConnector:
|
||||
|
||||
|
||||
class _DNSCacheTable:
|
||||
- def __init__(self, ttl: Optional[float] = None) -> None:
|
||||
- self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[Dict[str, Any]], int]] = {}
|
||||
+ def __init__(self, ttl: Optional[float] = None, max_size: int = 1000) -> None:
|
||||
+ self._addrs_rr: OrderedDict[
|
||||
+ Tuple[str, int], Tuple[Iterator[Dict[str, Any]], int]
|
||||
+ ] = OrderedDict()
|
||||
self._timestamps: Dict[Tuple[str, int], float] = {}
|
||||
self._ttl = ttl
|
||||
+ self._max_size = max_size
|
||||
|
||||
def __contains__(self, host: object) -> bool:
|
||||
return host in self._addrs_rr
|
||||
|
||||
def add(self, key: Tuple[str, int], addrs: List[Dict[str, Any]]) -> None:
|
||||
+ if key in self._addrs_rr:
|
||||
+ self._addrs_rr.move_to_end(key)
|
||||
+
|
||||
self._addrs_rr[key] = (cycle(addrs), len(addrs))
|
||||
|
||||
if self._ttl is not None:
|
||||
self._timestamps[key] = monotonic()
|
||||
|
||||
+ if len(self._addrs_rr) > self._max_size:
|
||||
+ oldest_key, _ = self._addrs_rr.popitem(last=False)
|
||||
+ self._timestamps.pop(oldest_key, None)
|
||||
+
|
||||
def remove(self, key: Tuple[str, int]) -> None:
|
||||
self._addrs_rr.pop(key, None)
|
||||
-
|
||||
- if self._ttl is not None:
|
||||
- self._timestamps.pop(key, None)
|
||||
+ self._timestamps.pop(key, None)
|
||||
|
||||
def clear(self) -> None:
|
||||
self._addrs_rr.clear()
|
||||
@@ -719,6 +727,7 @@ class _DNSCacheTable:
|
||||
addrs = list(islice(loop, length))
|
||||
# Consume one more element to shift internal state of `cycle`
|
||||
next(loop)
|
||||
+ self._addrs_rr.move_to_end(key)
|
||||
return addrs
|
||||
|
||||
def expired(self, key: Tuple[str, int]) -> bool:
|
||||
@@ -760,6 +769,7 @@ class TCPConnector(BaseConnector):
|
||||
fingerprint: Optional[bytes] = None,
|
||||
use_dns_cache: bool = True,
|
||||
ttl_dns_cache: Optional[int] = 10,
|
||||
+ dns_cache_max_size: int = 1000,
|
||||
family: int = 0,
|
||||
ssl_context: Optional[SSLContext] = None,
|
||||
ssl: Union[bool, Fingerprint, SSLContext] = True,
|
||||
@@ -789,7 +799,9 @@ class TCPConnector(BaseConnector):
|
||||
self._resolver = resolver
|
||||
|
||||
self._use_dns_cache = use_dns_cache
|
||||
- self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)
|
||||
+ self._cached_hosts = _DNSCacheTable(
|
||||
+ ttl=ttl_dns_cache, max_size=dns_cache_max_size
|
||||
+ )
|
||||
self._throttle_dns_events: Dict[Tuple[str, int], EventResultOrError] = {}
|
||||
self._family = family
|
||||
self._local_addr = local_addr
|
||||
diff --git a/tests/test_connector.py b/tests/test_connector.py
|
||||
index 02e48bc10..dd5e2c9e1 100644
|
||||
--- a/tests/test_connector.py
|
||||
+++ b/tests/test_connector.py
|
||||
@@ -2197,6 +2197,25 @@ async def test_named_pipe_connector(
|
||||
|
||||
|
||||
class TestDNSCacheTable:
|
||||
+ host1 = ("localhost", 80)
|
||||
+ host2 = ("foo", 80)
|
||||
+ result1 = {
|
||||
+ "hostname": "localhost",
|
||||
+ "host": "127.0.0.1",
|
||||
+ "port": 80,
|
||||
+ "family": socket.AF_INET,
|
||||
+ "proto": 0,
|
||||
+ "flags": socket.AI_NUMERICHOST,
|
||||
+ }
|
||||
+ result2 = {
|
||||
+ "hostname": "foo",
|
||||
+ "host": "127.0.0.2",
|
||||
+ "port": 80,
|
||||
+ "family": socket.AF_INET,
|
||||
+ "proto": 0,
|
||||
+ "flags": socket.AI_NUMERICHOST,
|
||||
+ }
|
||||
+
|
||||
@pytest.fixture
|
||||
def dns_cache_table(self):
|
||||
return _DNSCacheTable()
|
||||
@@ -2282,6 +2301,63 @@ class TestDNSCacheTable:
|
||||
addrs = dns_cache_table.next_addrs("foo")
|
||||
assert addrs == ["127.0.0.1"]
|
||||
|
||||
+ def test_max_size_eviction(self) -> None:
|
||||
+ table = _DNSCacheTable(max_size=2)
|
||||
+
|
||||
+ table.add(self.host1, [self.result1])
|
||||
+ table.add(self.host2, [self.result2])
|
||||
+
|
||||
+ host3 = ("example.com", 80)
|
||||
+ result3 = {
|
||||
+ **self.result1,
|
||||
+ "hostname": "example.com",
|
||||
+ "host": "1.2.3.4",
|
||||
+ }
|
||||
+ table.add(host3, [result3])
|
||||
+
|
||||
+ assert len(table._addrs_rr) == 2
|
||||
+ assert self.host1 not in table._addrs_rr
|
||||
+ assert host3 in table._addrs_rr
|
||||
+
|
||||
+ def test_lru_eviction(self) -> None:
|
||||
+ table = _DNSCacheTable(max_size=2)
|
||||
+
|
||||
+ table.add(self.host1, [self.result1])
|
||||
+ table.add(self.host2, [self.result2])
|
||||
+
|
||||
+ table.next_addrs(self.host1)
|
||||
+
|
||||
+ host3 = ("example.com", 80)
|
||||
+ result3 = {
|
||||
+ **self.result1,
|
||||
+ "hostname": "example.com",
|
||||
+ "host": "1.2.3.4",
|
||||
+ }
|
||||
+ table.add(host3, [result3])
|
||||
+
|
||||
+ assert self.host1 in table._addrs_rr
|
||||
+ assert self.host2 not in table._addrs_rr
|
||||
+
|
||||
+ def test_lru_eviction_add(self) -> None:
|
||||
+ table = _DNSCacheTable(max_size=2)
|
||||
+
|
||||
+ table.add(self.host1, [self.result1])
|
||||
+ table.add(self.host2, [self.result2])
|
||||
+
|
||||
+ # Re-add, thus making host1 the most recently used.
|
||||
+ table.add(self.host1, [self.result1])
|
||||
+
|
||||
+ host3 = ("example.com", 80)
|
||||
+ result3 = {
|
||||
+ **self.result1,
|
||||
+ "hostname": "example.com",
|
||||
+ "host": "1.2.3.4",
|
||||
+ }
|
||||
+ table.add(host3, [result3])
|
||||
+
|
||||
+ assert self.host1 in table._addrs_rr
|
||||
+ assert self.host2 not in table._addrs_rr
|
||||
+
|
||||
|
||||
async def test_connector_cache_trace_race():
|
||||
class DummyTracer:
|
||||
--
|
||||
2.35.6
|
||||
|
||||
Reference in New Issue
Block a user