Skip to content

Conversation

@digitalresistor
Copy link
Member

When we accept() a connection we get the remote address and we pass it to HTTPChannel, then in wasyncore.dispatcher we were calling getpeername() again to get the same remote address that we already had.

This would cause an issue if the remote client had sent data, but closed the connection before getpeername() because the wasyncore.dispatcher would set the channel to no longer being connected.

Further down the line this would cause issues whereby handle_write would loop over and over because it would mark itself as selectable but the socket would never actually get torn down.

Closes #418
Supersedes #419

No longer call getpeername() on the remote socket either, as it is not
necessary for any of the places where waitress requires that self.addr
in a subclass of the dispatcher needs it.

This removes a race condition when setting up a HTTPChannel where we
accepted the socket, and know the remote address, yet call getpeername()
again which would have the unintended side effect of potentially setting
self.connected to False because the remote has already shut down part of
the socket.

This issue was uncovered in #418, where the server would go into a hard
loop because self.connected was used in various parts of the code base.
Calling handle_close() multiple times does not hurt anything, and is
safe.
@digitalresistor digitalresistor force-pushed the bugfix/remove-race-condition branch 2 times, most recently from ef3833d to ff7e3c1 Compare March 3, 2024 23:54
This avoids calling close() twice on the same socket if self.close() or
self.handle_close() is called multiple times
@djay
Copy link

djay commented Apr 26, 2024

@digitalresistor it's been running for a few weeks with no problem. the pentests still happen and we haven't see any problems.

@vondele
Copy link

vondele commented Jul 7, 2024

great, find and thanks for fixing this. We have been running a server at https://tests.stockfishchess.org/tests that almost reads like the description of the testcase in #418 (comment) and have seen this happen multiple times in the past, if the load on the server was high (with dropped connections by nginx / nginx reboots), almost on a daily basis (most recently discussed as official-stockfish/fishtest#2094 ... but we had no real clue).

We'd be happy to upgrade waitress to an eventual 3.0.1 as mentioned in 3495674 . Is there a timeline for that (also in light of the green CI)?

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Feb 5, 2025
3.0.2 (2024-11-16)

Security

- When using Waitress to process trusted proxy headers, Waitress will now
  update the headers to drop any untrusted values, thereby making sure that
  WSGI apps only get trusted and validated values that Waitress itself used to
  update the environ. See Pylons/waitress#452 and
  Pylons/waitress#451


3.0.1 (2024-10-28)

Backward Incompatibilities

- Python 3.8 is no longer supported.
  See Pylons/waitress#445.

Features

- Added support for Python 3.13.
  See Pylons/waitress#445.

Security

- Fix a bug that would lead to Waitress busy looping on select() on a half-open
  socket due to a race condition that existed when creating a new HTTPChannel.
  See Pylons/waitress#435,
  Pylons/waitress#418 and
  GHSA-3f84-rpwh-47g6

  With thanks to Dylan Jay and Dieter Maurer for their extensive debugging and
  helping track this down.

- No longer strip the header values before passing them to the WSGI environ.
  See Pylons/waitress#434 and
  Pylons/waitress#432

- Fix a race condition in Waitress when `channel_request_lookahead` is enabled
  that could lead to HTTP request smuggling.
arnout pushed a commit to buildroot/buildroot that referenced this pull request Feb 7, 2025
Both 3.0.1 and 3.0.2 fix security issues.

In 3.0.1:

* Fix a bug that would lead to Waitress busy looping on select() on a
  half-open socket due to a race condition that existed when creating a
  new HTTPChannel. See Pylons/waitress#435,
  Pylons/waitress#418 and
  GHSA-3f84-rpwh-47g6

* With thanks to Dylan Jay and Dieter Maurer for their extensive
  debugging and helping track this down.

* No longer strip the header values before passing them to the WSGI
  environ. See Pylons/waitress#434 and
  Pylons/waitress#432

* Fix a race condition in Waitress when channel_request_lookahead is
  enabled that could lead to HTTP request smuggling.
  See GHSA-9298-4cf8-g4wj

In 3.0.2:

* When using Waitress to process trusted proxy headers, Waitress will
  now update the headers to drop any untrusted values, thereby making sure
  that WSGI apps only get trusted and validated values that Waitress
  itself used to update the environ. See
  Pylons/waitress#452 and
  Pylons/waitress#451

Full Changelog:
https://docs.pylonsproject.org/projects/waitress/en/latest/#change-history

Signed-off-by: Marcus Hoffmann <buildroot@bubu1.eu>
Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

100% cpu in mainthread due to not closing properly? (channel.connected == False)

4 participants