1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
From f2ffe56f990a74450143901ac1cfd7138f75ec78 Mon Sep 17 00:00:00 2001
From: Delta Regeer <bertjw@regeer.org>
Date: Sat, 26 Oct 2024 22:10:36 -0600
Subject: [PATCH] Make DummySock() look more like an actual socket
This forces DummySock() to look like a properly connected socket where
there is a buffer that is read from by the remote, and a buffer that is
written to by the remote.
The local side does the opposite, this way data written by the local
side can be read by the remote without operating on the same buffer.
CVE: CVE-2024-49768
Upstream-Status: Backport [https://github.com/Pylons/waitress/commit/6943dcf556610ece2ff3cddb39e59a05ef110661]
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
---
tests/test_channel.py | 57 +++++++++++++++++++++++++++++++++----------
1 file changed, 44 insertions(+), 13 deletions(-)
diff --git a/tests/test_channel.py b/tests/test_channel.py
index 8467ae7..7d677e9 100644
--- a/tests/test_channel.py
+++ b/tests/test_channel.py
@@ -18,7 +18,7 @@ class TestHTTPChannel(unittest.TestCase):
map = {}
inst = self._makeOne(sock, "127.0.0.1", adj, map=map)
inst.outbuf_lock = DummyLock()
- return inst, sock, map
+ return inst, sock.local(), map
def test_ctor(self):
inst, _, map = self._makeOneWithMap()
@@ -218,7 +218,7 @@ class TestHTTPChannel(unittest.TestCase):
def send(_):
return 0
- sock.send = send
+ sock.remote.send = send
wrote = inst.write_soon(b"a")
self.assertEqual(wrote, 1)
@@ -236,7 +236,7 @@ class TestHTTPChannel(unittest.TestCase):
def send(_):
return 0
- sock.send = send
+ sock.remote.send = send
outbufs = inst.outbufs
wrote = inst.write_soon(wrapper)
@@ -270,7 +270,7 @@ class TestHTTPChannel(unittest.TestCase):
def send(_):
return 0
- sock.send = send
+ sock.remote.send = send
inst.adj.outbuf_high_watermark = 3
inst.current_outbuf_count = 4
@@ -286,7 +286,7 @@ class TestHTTPChannel(unittest.TestCase):
def send(_):
return 0
- sock.send = send
+ sock.remote.send = send
inst.adj.outbuf_high_watermark = 3
inst.total_outbufs_len = 4
@@ -315,7 +315,7 @@ class TestHTTPChannel(unittest.TestCase):
inst.connected = False
raise Exception()
- sock.send = send
+ sock.remote.send = send
inst.adj.outbuf_high_watermark = 3
inst.total_outbufs_len = 4
@@ -345,7 +345,7 @@ class TestHTTPChannel(unittest.TestCase):
inst.connected = False
raise Exception()
- sock.send = send
+ sock.remote.send = send
wrote = inst.write_soon(b"xyz")
self.assertEqual(wrote, 3)
@@ -376,7 +376,7 @@ class TestHTTPChannel(unittest.TestCase):
inst.total_outbufs_len = len(inst.outbufs[0])
inst.adj.send_bytes = 1
inst.adj.outbuf_high_watermark = 2
- sock.send = lambda x, do_close=True: False
+ sock.remote.send = lambda x, do_close=True: False
inst.will_close = False
inst.last_activity = 0
result = inst.handle_write()
@@ -400,7 +400,7 @@ class TestHTTPChannel(unittest.TestCase):
def test__flush_some_full_outbuf_socket_returns_zero(self):
inst, sock, map = self._makeOneWithMap()
- sock.send = lambda x: False
+ sock.remote.send = lambda x: False
inst.outbufs[0].append(b"abc")
inst.total_outbufs_len = sum(len(x) for x in inst.outbufs)
result = inst._flush_some()
@@ -907,7 +907,8 @@ class DummySock:
closed = False
def __init__(self):
- self.sent = b""
+ self.local_sent = b""
+ self.remote_sent = b""
def setblocking(self, *arg):
self.blocking = True
@@ -925,14 +926,44 @@ class DummySock:
self.closed = True
def send(self, data):
- self.sent += data
+ self.remote_sent += data
return len(data)
def recv(self, buffer_size):
- result = self.sent[:buffer_size]
- self.sent = self.sent[buffer_size:]
+ result = self.local_sent[:buffer_size]
+ self.local_sent = self.local_sent[buffer_size:]
return result
+ def local(self):
+ outer = self
+
+ class LocalDummySock:
+ def send(self, data):
+ outer.local_sent += data
+ return len(data)
+
+ def recv(self, buffer_size):
+ result = outer.remote_sent[:buffer_size]
+ outer.remote_sent = outer.remote_sent[buffer_size:]
+ return result
+
+ def close(self):
+ outer.closed = True
+
+ @property
+ def sent(self):
+ return outer.remote_sent
+
+ @property
+ def closed(self):
+ return outer.closed
+
+ @property
+ def remote(self):
+ return outer
+
+ return LocalDummySock()
+
class DummyLock:
notified = False
|