From aa161b98cc787f266d8ef358f00fc5b2b3944157 Mon Sep 17 00:00:00 2001 From: Delta Regeer Date: Sun, 3 Mar 2024 16:35:39 -0700 Subject: [PATCH] Remove code not used by waitress from vendored asyncore CVE: CVE-2024-49769 Upstream-Status: Backport [https://github.com/Pylons/waitress/commit/63678e652d912e67621580123c603e37c319d8c4] Signed-off-by: Gyorgy Sarvari --- src/waitress/wasyncore.py | 45 ------------------ tests/test_wasyncore.py | 96 ++++++++------------------------------- 2 files changed, 18 insertions(+), 123 deletions(-) diff --git a/src/waitress/wasyncore.py b/src/waitress/wasyncore.py index b5ddce2..117f78a 100644 --- a/src/waitress/wasyncore.py +++ b/src/waitress/wasyncore.py @@ -379,23 +379,6 @@ class dispatcher: self.addr = addr return self.socket.bind(addr) - def connect(self, address): - self.connected = False - self.connecting = True - err = self.socket.connect_ex(address) - if ( - err in (EINPROGRESS, EALREADY, EWOULDBLOCK) - or err == EINVAL - and os.name == "nt" - ): # pragma: no cover - self.addr = address - return - if err in (0, EISCONN): - self.addr = address - self.handle_connect_event() - else: - raise OSError(err, errorcode[err]) - def accept(self): # XXX can return either an address pair or None try: @@ -557,34 +540,6 @@ class dispatcher: self.close() -# --------------------------------------------------------------------------- -# adds simple buffered output capability, useful for simple clients. -# [for more sophisticated usage use asynchat.async_chat] -# --------------------------------------------------------------------------- - - -class dispatcher_with_send(dispatcher): - def __init__(self, sock=None, map=None): - dispatcher.__init__(self, sock, map) - self.out_buffer = b"" - - def initiate_send(self): - num_sent = 0 - num_sent = dispatcher.send(self, self.out_buffer[:65536]) - self.out_buffer = self.out_buffer[num_sent:] - - handle_write = initiate_send - - def writable(self): - return (not self.connected) or len(self.out_buffer) - - def send(self, data): - if self.debug: # pragma: no cover - self.log_info("sending %s" % repr(data)) - self.out_buffer = self.out_buffer + data - self.initiate_send() - - def close_all(map=None, ignore_all=False): if map is None: # pragma: no cover map = socket_map diff --git a/tests/test_wasyncore.py b/tests/test_wasyncore.py index 5f38bd9..44b8e19 100644 --- a/tests/test_wasyncore.py +++ b/tests/test_wasyncore.py @@ -1,6 +1,7 @@ import _thread as thread import contextlib import errno +from errno import EALREADY, EINPROGRESS, EINVAL, EISCONN, EWOULDBLOCK, errorcode import functools import gc from io import BytesIO @@ -641,62 +642,6 @@ class DispatcherTests(unittest.TestCase): self.assertTrue(err != "") -class dispatcherwithsend_noread(asyncore.dispatcher_with_send): # pragma: no cover - def readable(self): - return False - - def handle_connect(self): - pass - - -class DispatcherWithSendTests(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - asyncore.close_all() - - @reap_threads - def test_send(self): - evt = threading.Event() - sock = socket.socket() - sock.settimeout(3) - port = bind_port(sock) - - cap = BytesIO() - args = (evt, cap, sock) - t = threading.Thread(target=capture_server, args=args) - t.start() - try: - # wait a little longer for the server to initialize (it sometimes - # refuses connections on slow machines without this wait) - time.sleep(0.2) - - data = b"Suppose there isn't a 16-ton weight?" - d = dispatcherwithsend_noread() - d.create_socket() - d.connect((HOST, port)) - - # give time for socket to connect - time.sleep(0.1) - - d.send(data) - d.send(data) - d.send(b"\n") - - n = 1000 - - while d.out_buffer and n > 0: # pragma: no cover - asyncore.poll() - n -= 1 - - evt.wait() - - self.assertEqual(cap.getvalue(), data * 2) - finally: - join_thread(t, timeout=TIMEOUT) - - @unittest.skipUnless( hasattr(asyncore, "file_wrapper"), "asyncore.file_wrapper required" ) @@ -839,6 +784,23 @@ class BaseClient(BaseTestHandler): self.create_socket(family) self.connect(address) + def connect(self, address): + self.connected = False + self.connecting = True + err = self.socket.connect_ex(address) + if ( + err in (EINPROGRESS, EALREADY, EWOULDBLOCK) + or err == EINVAL + and os.name == "nt" + ): # pragma: no cover + self.addr = address + return + if err in (0, EISCONN): + self.addr = address + self.handle_connect_event() + else: + raise OSError(err, errorcode[err]) + def handle_connect(self): pass @@ -1486,13 +1448,6 @@ class Test_dispatcher(unittest.TestCase): inst.set_reuse_addr() self.assertTrue(sock.errored) - def test_connect_raise_socket_error(self): - sock = dummysocket() - map = {} - sock.connect_ex = lambda *arg: 1 - inst = self._makeOne(sock=sock, map=map) - self.assertRaises(socket.error, inst.connect, 0) - def test_accept_raise_TypeError(self): sock = dummysocket() map = {} @@ -1661,21 +1616,6 @@ class Test_dispatcher(unittest.TestCase): self.assertTrue(sock.closed) -class Test_dispatcher_with_send(unittest.TestCase): - def _makeOne(self, sock=None, map=None): - from waitress.wasyncore import dispatcher_with_send - - return dispatcher_with_send(sock=sock, map=map) - - def test_writable(self): - sock = dummysocket() - map = {} - inst = self._makeOne(sock=sock, map=map) - inst.out_buffer = b"123" - inst.connected = True - self.assertTrue(inst.writable()) - - class Test_close_all(unittest.TestCase): def _callFUT(self, map=None, ignore_all=False): from waitress.wasyncore import close_all