summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/python/python3/CVE-2025-13836.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/python/python3/CVE-2025-13836.patch')
-rw-r--r--meta/recipes-devtools/python/python3/CVE-2025-13836.patch163
1 files changed, 163 insertions, 0 deletions
diff --git a/meta/recipes-devtools/python/python3/CVE-2025-13836.patch b/meta/recipes-devtools/python/python3/CVE-2025-13836.patch
new file mode 100644
index 0000000000..c4387b6019
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/CVE-2025-13836.patch
@@ -0,0 +1,163 @@
1From 289f29b0fe38baf2d7cb5854f4bb573cc34a6a15 Mon Sep 17 00:00:00 2001
2From: "Miss Islington (bot)"
3 <31488909+miss-islington@users.noreply.github.com>
4Date: Fri, 5 Dec 2025 16:21:57 +0100
5Subject: [PATCH] [3.13] gh-119451: Fix a potential denial of service in
6 http.client (GH-119454) (#142139)
7
8gh-119451: Fix a potential denial of service in http.client (GH-119454)
9
10Reading the whole body of the HTTP response could cause OOM if
11the Content-Length value is too large even if the server does not send
12a large amount of data. Now the HTTP client reads large data by chunks,
13therefore the amount of consumed memory is proportional to the amount
14of sent data.
15(cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5)
16
17CVE: CVE-2025-13836
18Upstream-Status: Backport [https://github.com/python/cpython/commit/289f29b0fe38baf2d7cb5854f4bb573cc34a6a15]
19Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
20---
21 Lib/http/client.py | 28 ++++++--
22 Lib/test/test_httplib.py | 66 +++++++++++++++++++
23 ...-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5 ++
24 3 files changed, 95 insertions(+), 4 deletions(-)
25 create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
26
27diff --git a/Lib/http/client.py b/Lib/http/client.py
28index d1b7b10..c8ab5b7 100644
29--- a/Lib/http/client.py
30+++ b/Lib/http/client.py
31@@ -111,6 +111,11 @@ responses = {v: v.phrase for v in http.HTTPStatus.__members__.values()}
32 _MAXLINE = 65536
33 _MAXHEADERS = 100
34
35+# Data larger than this will be read in chunks, to prevent extreme
36+# overallocation.
37+_MIN_READ_BUF_SIZE = 1 << 20
38+
39+
40 # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
41 #
42 # VCHAR = %x21-7E
43@@ -628,10 +633,25 @@ class HTTPResponse(io.BufferedIOBase):
44 reading. If the bytes are truly not available (due to EOF), then the
45 IncompleteRead exception can be used to detect the problem.
46 """
47- data = self.fp.read(amt)
48- if len(data) < amt:
49- raise IncompleteRead(data, amt-len(data))
50- return data
51+ cursize = min(amt, _MIN_READ_BUF_SIZE)
52+ data = self.fp.read(cursize)
53+ if len(data) >= amt:
54+ return data
55+ if len(data) < cursize:
56+ raise IncompleteRead(data, amt - len(data))
57+
58+ data = io.BytesIO(data)
59+ data.seek(0, 2)
60+ while True:
61+ # This is a geometric increase in read size (never more than
62+ # doubling out the current length of data per loop iteration).
63+ delta = min(cursize, amt - cursize)
64+ data.write(self.fp.read(delta))
65+ if data.tell() >= amt:
66+ return data.getvalue()
67+ cursize += delta
68+ if data.tell() < cursize:
69+ raise IncompleteRead(data.getvalue(), amt - data.tell())
70
71 def _safe_readinto(self, b):
72 """Same as _safe_read, but for reading into a buffer."""
73diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
74index 77152cf..89ec5f6 100644
75--- a/Lib/test/test_httplib.py
76+++ b/Lib/test/test_httplib.py
77@@ -1226,6 +1226,72 @@ class BasicTest(TestCase):
78 thread.join()
79 self.assertEqual(result, b"proxied data\n")
80
81+ def test_large_content_length(self):
82+ serv = socket.create_server((HOST, 0))
83+ self.addCleanup(serv.close)
84+
85+ def run_server():
86+ [conn, address] = serv.accept()
87+ with conn:
88+ while conn.recv(1024):
89+ conn.sendall(
90+ b"HTTP/1.1 200 Ok\r\n"
91+ b"Content-Length: %d\r\n"
92+ b"\r\n" % size)
93+ conn.sendall(b'A' * (size//3))
94+ conn.sendall(b'B' * (size - size//3))
95+
96+ thread = threading.Thread(target=run_server)
97+ thread.start()
98+ self.addCleanup(thread.join, 1.0)
99+
100+ conn = client.HTTPConnection(*serv.getsockname())
101+ try:
102+ for w in range(15, 27):
103+ size = 1 << w
104+ conn.request("GET", "/")
105+ with conn.getresponse() as response:
106+ self.assertEqual(len(response.read()), size)
107+ finally:
108+ conn.close()
109+ thread.join(1.0)
110+
111+ def test_large_content_length_truncated(self):
112+ serv = socket.create_server((HOST, 0))
113+ self.addCleanup(serv.close)
114+
115+ def run_server():
116+ while True:
117+ [conn, address] = serv.accept()
118+ with conn:
119+ conn.recv(1024)
120+ if not size:
121+ break
122+ conn.sendall(
123+ b"HTTP/1.1 200 Ok\r\n"
124+ b"Content-Length: %d\r\n"
125+ b"\r\n"
126+ b"Text" % size)
127+
128+ thread = threading.Thread(target=run_server)
129+ thread.start()
130+ self.addCleanup(thread.join, 1.0)
131+
132+ conn = client.HTTPConnection(*serv.getsockname())
133+ try:
134+ for w in range(18, 65):
135+ size = 1 << w
136+ conn.request("GET", "/")
137+ with conn.getresponse() as response:
138+ self.assertRaises(client.IncompleteRead, response.read)
139+ conn.close()
140+ finally:
141+ conn.close()
142+ size = 0
143+ conn.request("GET", "/")
144+ conn.close()
145+ thread.join(1.0)
146+
147 def test_putrequest_override_domain_validation(self):
148 """
149 It should be possible to override the default validation
150diff --git a/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
151new file mode 100644
152index 0000000..6d6f25c
153--- /dev/null
154+++ b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
155@@ -0,0 +1,5 @@
156+Fix a potential memory denial of service in the :mod:`http.client` module.
157+When connecting to a malicious server, it could cause
158+an arbitrary amount of memory to be allocated.
159+This could have led to symptoms including a :exc:`MemoryError`, swapping, out
160+of memory (OOM) killed processes or containers, or even system crashes.
161--
1622.50.1
163