summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGyorgy Sarvari <skandigraun@gmail.com>2026-01-07 10:27:46 +0100
committerGyorgy Sarvari <skandigraun@gmail.com>2026-01-08 22:03:03 +0100
commit1ea440cd62d4fc1a0cd4d391bef16cc0ee894458 (patch)
tree62350624e99870669a7d036776fa6a4f66525c06
parente330e3508db2dabb575d25a85967d7bf72af8a06 (diff)
downloadmeta-openembedded-1ea440cd62d4fc1a0cd4d391bef16cc0ee894458.tar.gz
python3-waitress: patch CVE-2024-49768
Details: https://nvd.nist.gov/vuln/detail/CVE-2024-49768 Pick the patch mentioned in the NVD report (which is a merge commit, and the patches here are the individual commits from that merge) Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
-rw-r--r--meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-1.patch162
-rw-r--r--meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-2.patch89
-rw-r--r--meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-3.patch60
-rw-r--r--meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-4.patch34
-rw-r--r--meta-python/recipes-devtools/python/python3-waitress_2.1.2.bb5
5 files changed, 350 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-1.patch b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-1.patch
new file mode 100644
index 0000000000..5d80a267fd
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-1.patch
@@ -0,0 +1,162 @@
1From f2ffe56f990a74450143901ac1cfd7138f75ec78 Mon Sep 17 00:00:00 2001
2From: Delta Regeer <bertjw@regeer.org>
3Date: Sat, 26 Oct 2024 22:10:36 -0600
4Subject: [PATCH] Make DummySock() look more like an actual socket
5
6This forces DummySock() to look like a properly connected socket where
7there is a buffer that is read from by the remote, and a buffer that is
8written to by the remote.
9
10The local side does the opposite, this way data written by the local
11side can be read by the remote without operating on the same buffer.
12
13CVE: CVE-2024-49768
14Upstream-Status: Backport [https://github.com/Pylons/waitress/commit/6943dcf556610ece2ff3cddb39e59a05ef110661]
15Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
16---
17 tests/test_channel.py | 57 +++++++++++++++++++++++++++++++++----------
18 1 file changed, 44 insertions(+), 13 deletions(-)
19
20diff --git a/tests/test_channel.py b/tests/test_channel.py
21index 8467ae7..7d677e9 100644
22--- a/tests/test_channel.py
23+++ b/tests/test_channel.py
24@@ -18,7 +18,7 @@ class TestHTTPChannel(unittest.TestCase):
25 map = {}
26 inst = self._makeOne(sock, "127.0.0.1", adj, map=map)
27 inst.outbuf_lock = DummyLock()
28- return inst, sock, map
29+ return inst, sock.local(), map
30
31 def test_ctor(self):
32 inst, _, map = self._makeOneWithMap()
33@@ -218,7 +218,7 @@ class TestHTTPChannel(unittest.TestCase):
34 def send(_):
35 return 0
36
37- sock.send = send
38+ sock.remote.send = send
39
40 wrote = inst.write_soon(b"a")
41 self.assertEqual(wrote, 1)
42@@ -236,7 +236,7 @@ class TestHTTPChannel(unittest.TestCase):
43 def send(_):
44 return 0
45
46- sock.send = send
47+ sock.remote.send = send
48
49 outbufs = inst.outbufs
50 wrote = inst.write_soon(wrapper)
51@@ -270,7 +270,7 @@ class TestHTTPChannel(unittest.TestCase):
52 def send(_):
53 return 0
54
55- sock.send = send
56+ sock.remote.send = send
57
58 inst.adj.outbuf_high_watermark = 3
59 inst.current_outbuf_count = 4
60@@ -286,7 +286,7 @@ class TestHTTPChannel(unittest.TestCase):
61 def send(_):
62 return 0
63
64- sock.send = send
65+ sock.remote.send = send
66
67 inst.adj.outbuf_high_watermark = 3
68 inst.total_outbufs_len = 4
69@@ -315,7 +315,7 @@ class TestHTTPChannel(unittest.TestCase):
70 inst.connected = False
71 raise Exception()
72
73- sock.send = send
74+ sock.remote.send = send
75
76 inst.adj.outbuf_high_watermark = 3
77 inst.total_outbufs_len = 4
78@@ -345,7 +345,7 @@ class TestHTTPChannel(unittest.TestCase):
79 inst.connected = False
80 raise Exception()
81
82- sock.send = send
83+ sock.remote.send = send
84
85 wrote = inst.write_soon(b"xyz")
86 self.assertEqual(wrote, 3)
87@@ -376,7 +376,7 @@ class TestHTTPChannel(unittest.TestCase):
88 inst.total_outbufs_len = len(inst.outbufs[0])
89 inst.adj.send_bytes = 1
90 inst.adj.outbuf_high_watermark = 2
91- sock.send = lambda x, do_close=True: False
92+ sock.remote.send = lambda x, do_close=True: False
93 inst.will_close = False
94 inst.last_activity = 0
95 result = inst.handle_write()
96@@ -400,7 +400,7 @@ class TestHTTPChannel(unittest.TestCase):
97
98 def test__flush_some_full_outbuf_socket_returns_zero(self):
99 inst, sock, map = self._makeOneWithMap()
100- sock.send = lambda x: False
101+ sock.remote.send = lambda x: False
102 inst.outbufs[0].append(b"abc")
103 inst.total_outbufs_len = sum(len(x) for x in inst.outbufs)
104 result = inst._flush_some()
105@@ -907,7 +907,8 @@ class DummySock:
106 closed = False
107
108 def __init__(self):
109- self.sent = b""
110+ self.local_sent = b""
111+ self.remote_sent = b""
112
113 def setblocking(self, *arg):
114 self.blocking = True
115@@ -925,14 +926,44 @@ class DummySock:
116 self.closed = True
117
118 def send(self, data):
119- self.sent += data
120+ self.remote_sent += data
121 return len(data)
122
123 def recv(self, buffer_size):
124- result = self.sent[:buffer_size]
125- self.sent = self.sent[buffer_size:]
126+ result = self.local_sent[:buffer_size]
127+ self.local_sent = self.local_sent[buffer_size:]
128 return result
129
130+ def local(self):
131+ outer = self
132+
133+ class LocalDummySock:
134+ def send(self, data):
135+ outer.local_sent += data
136+ return len(data)
137+
138+ def recv(self, buffer_size):
139+ result = outer.remote_sent[:buffer_size]
140+ outer.remote_sent = outer.remote_sent[buffer_size:]
141+ return result
142+
143+ def close(self):
144+ outer.closed = True
145+
146+ @property
147+ def sent(self):
148+ return outer.remote_sent
149+
150+ @property
151+ def closed(self):
152+ return outer.closed
153+
154+ @property
155+ def remote(self):
156+ return outer
157+
158+ return LocalDummySock()
159+
160
161 class DummyLock:
162 notified = False
diff --git a/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-2.patch b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-2.patch
new file mode 100644
index 0000000000..88d6aba0e2
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-2.patch
@@ -0,0 +1,89 @@
1From 7f40812194ebbf189692f530422204b41204eecb Mon Sep 17 00:00:00 2001
2From: Delta Regeer <bertjw@regeer.org>
3Date: Sat, 26 Oct 2024 22:12:14 -0600
4Subject: [PATCH] Add a new test to validate the lookahead race condition
5
6CVE: CVE-2024-49768
7Upstream-Status: Backport [https://github.com/Pylons/waitress/commit/6943dcf556610ece2ff3cddb39e59a05ef110661]
8Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
9---
10 tests/test_channel.py | 55 ++++++++++++++++++++++++++++++++++++++++++-
11 1 file changed, 54 insertions(+), 1 deletion(-)
12
13diff --git a/tests/test_channel.py b/tests/test_channel.py
14index 7d677e9..d798091 100644
15--- a/tests/test_channel.py
16+++ b/tests/test_channel.py
17@@ -805,11 +805,12 @@ class TestHTTPChannelLookahead(TestHTTPChannel):
18 )
19 return [body]
20
21- def _make_app_with_lookahead(self):
22+ def _make_app_with_lookahead(self, recv_bytes=8192):
23 """
24 Setup a channel with lookahead and store it and the socket in self
25 """
26 adj = DummyAdjustments()
27+ adj.recv_bytes = recv_bytes
28 adj.channel_request_lookahead = 5
29 channel, sock, map = self._makeOneWithMap(adj=adj)
30 channel.server.application = self.app_check_disconnect
31@@ -901,6 +902,58 @@ class TestHTTPChannelLookahead(TestHTTPChannel):
32 self.assertEqual(data.split("\r\n")[-1], "finished")
33 self.assertEqual(self.request_body, b"x")
34
35+ def test_lookahead_bad_request_drop_extra_data(self):
36+ """
37+ Send two requests, the first one being bad, split on the recv_bytes
38+ limit, then emulate a race that could happen whereby we read data from
39+ the socket while the service thread is cleaning up due to an error
40+ processing the request.
41+ """
42+
43+ invalid_request = [
44+ "GET / HTTP/1.1",
45+ "Host: localhost:8080",
46+ "Content-length: -1",
47+ "",
48+ ]
49+
50+ invalid_request_len = len("".join([x + "\r\n" for x in invalid_request]))
51+
52+ second_request = [
53+ "POST / HTTP/1.1",
54+ "Host: localhost:8080",
55+ "Content-Length: 1",
56+ "",
57+ "x",
58+ ]
59+
60+ full_request = invalid_request + second_request
61+
62+ self._make_app_with_lookahead(recv_bytes=invalid_request_len)
63+ self._send(*full_request)
64+ self.channel.handle_read()
65+ self.assertEqual(len(self.channel.requests), 1)
66+ self.channel.server.tasks[0].service()
67+ self.assertTrue(self.channel.close_when_flushed)
68+ # Read all of the next request
69+ self.channel.handle_read()
70+ self.channel.handle_read()
71+ # Validate that there is no more data to be read
72+ self.assertEqual(self.sock.remote.local_sent, b"")
73+ # Validate that we dropped the data from the second read, and did not
74+ # create a new request
75+ self.assertEqual(len(self.channel.requests), 0)
76+ data = self.sock.recv(256).decode("ascii")
77+ self.assertFalse(self.channel.readable())
78+ self.assertTrue(self.channel.writable())
79+
80+ # Handle the write, which will close the socket
81+ self.channel.handle_write()
82+ self.assertTrue(self.sock.closed)
83+
84+ data = self.sock.recv(256)
85+ self.assertEqual(len(data), 0)
86+
87
88 class DummySock:
89 blocking = False
diff --git a/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-3.patch b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-3.patch
new file mode 100644
index 0000000000..086c569233
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-3.patch
@@ -0,0 +1,60 @@
1From 5cf72c7d9f60e96a3ca65e410098e11d8053749d Mon Sep 17 00:00:00 2001
2From: Delta Regeer <bertjw@regeer.org>
3Date: Sat, 26 Oct 2024 22:13:08 -0600
4Subject: [PATCH] Fix a race condition on recv_bytes boundary when request is
5 invalid
6
7A remote client may send a request that is exactly recv_bytes long,
8followed by a secondary request using HTTP pipelining.
9
10When request lookahead is disabled (default) we won't read any more
11requests, and when the first request fails due to a parsing error, we
12simply close the connection.
13
14However when request lookahead is enabled, it is possible to process and
15receive the first request, start sending the error message back to the
16client while we read the next request and queue it. This will allow the
17secondar request to be serviced by the worker thread while the
18connection should be closed.
19
20The fix here checks if we should not have read the data in the first
21place (because the conection is going to be torn down) while we hold the
22`requests_lock` which means the service thread can't be in the middle of
23flipping the `close_when_flushed` flag.
24
25CVE: CVE-2024-49768
26Upstream-Status: Backport [https://github.com/Pylons/waitress/commit/f4ba1c260cf17156b582c6252496213ddc96b591]
27Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
28---
29 src/waitress/channel.py | 11 ++++++++++-
30 1 file changed, 10 insertions(+), 1 deletion(-)
31
32diff --git a/src/waitress/channel.py b/src/waitress/channel.py
33index eb59dd3..756adce 100644
34--- a/src/waitress/channel.py
35+++ b/src/waitress/channel.py
36@@ -147,7 +147,7 @@ class HTTPChannel(wasyncore.dispatcher):
37 # 1. We're not already about to close the connection.
38 # 2. We're not waiting to flush remaining data before closing the
39 # connection
40- # 3. There are not too many tasks already queued
41+ # 3. There are not too many tasks already queued (if lookahead is enabled)
42 # 4. There's no data in the output buffer that needs to be sent
43 # before we potentially create a new task.
44
45@@ -203,6 +203,15 @@ class HTTPChannel(wasyncore.dispatcher):
46 return False
47
48 with self.requests_lock:
49+ # Don't bother processing anymore data if this connection is about
50+ # to close. This may happen if readable() returned True, on the
51+ # main thread before the service thread set the close_when_flushed
52+ # flag, and we read data but our service thread is attempting to
53+ # shut down the connection due to an error. We want to make sure we
54+ # do this while holding the request_lock so that we can't race
55+ if self.will_close or self.close_when_flushed:
56+ return False
57+
58 while data:
59 if self.request is None:
60 self.request = self.parser_class(self.adj)
diff --git a/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-4.patch b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-4.patch
new file mode 100644
index 0000000000..11c9dd4ccd
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-waitress/CVE-2024-49768-4.patch
@@ -0,0 +1,34 @@
1From c516dad4f749d1b1b1c675680a76c1f6d2523857 Mon Sep 17 00:00:00 2001
2From: Delta Regeer <bertjw@regeer.org>
3Date: Sat, 26 Oct 2024 22:22:32 -0600
4Subject: [PATCH] Add documentation for channel_request_lookahead
5
6CVE: CVE-2024-49768
7Upstream-Status: Backport [https://github.com/Pylons/waitress/commit/810a435f9e9e293bd3446a5ce2df86f59c4e7b1b]
8Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
9---
10 docs/arguments.rst | 14 ++++++++++++++
11 1 file changed, 14 insertions(+)
12
13diff --git a/docs/arguments.rst b/docs/arguments.rst
14index f9b9310..ba1797a 100644
15--- a/docs/arguments.rst
16+++ b/docs/arguments.rst
17@@ -301,3 +301,17 @@ url_prefix
18 be stripped of the prefix.
19
20 Default: ``''``
21+
22+channel_request_lookahead
23+ Sets the amount of requests we can continue to read from the socket, while
24+ we are processing current requests. The default value won't allow any
25+ lookahead, increase it above ``0`` to enable.
26+
27+ When enabled this inserts a callable ``waitress.client_disconnected`` into
28+ the environment that allows the task to check if the client disconnected
29+ while waiting for the response at strategic points in the execution and to
30+ cancel the operation.
31+
32+ Default: ``0``
33+
34+ .. versionadded:: 2.0.0
diff --git a/meta-python/recipes-devtools/python/python3-waitress_2.1.2.bb b/meta-python/recipes-devtools/python/python3-waitress_2.1.2.bb
index 061586b5df..dbb8b05e52 100644
--- a/meta-python/recipes-devtools/python/python3-waitress_2.1.2.bb
+++ b/meta-python/recipes-devtools/python/python3-waitress_2.1.2.bb
@@ -10,6 +10,11 @@ RDEPENDS:${PN} += " \
10 python3-logging \ 10 python3-logging \
11" 11"
12 12
13SRC_URI += "file://CVE-2024-49768-1.patch \
14 file://CVE-2024-49768-2.patch \
15 file://CVE-2024-49768-3.patch \
16 file://CVE-2024-49768-4.patch \
17 "
13SRC_URI[sha256sum] = "780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba" 18SRC_URI[sha256sum] = "780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"
14 19
15inherit python_setuptools_build_meta pypi 20inherit python_setuptools_build_meta pypi