[ python-Bugs-1685000 ] DoS asyncore vulnerability

SourceForge.net noreply at sourceforge.net
Fri Mar 30 19:22:12 CEST 2007


Bugs item #1685000, was opened at 2007-03-21 02:15
Message generated for change (Comment added) made by rushing
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1685000&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Python Library
Group: Python 2.5
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: billiejoex (billiejoex)
Assigned to: Nobody/Anonymous (nobody)
Summary: DoS asyncore vulnerability

Initial Comment:
DoS asyncore vulnerability

asyncore, independently if used with select() or poll(), suffers a DoS-type vulnerability when a high number of simultaneous connections to handle simultaneously is reached.
The number of maximum connections is system-dependent as well as the type of error raised.
I attached two simple Proof of Concept scripts demonstrating such bug.
If you want to try the behaviours listed below run the attached "asyncore_server.py" and "asyncore_client.py" scripts on your local workstation.

On my Windows XP system (Python 2.5), independently if asyncore has been used to develop a server or a client, the error is raised by select() inside asyncore's "poll" function when 512 (socket_map's elements) simultaneous connections are reached. 
Here's the traceback I get:

[...]
connections: 510
connections: 511
connections: 512
Traceback (most recent call last):
  File "C:\scripts\asyncore_server.py", line 38, in <module>
    asyncore.loop()
  File "C:\Python25\lib\asyncore.py", line 191, in loop
    poll_fun(timeout, map)
  File "C:\Python25\lib\asyncore.py", line 121, in poll
    r, w, e = select.select(r, w, e, timeout)
ValueError: too many file descriptors in select()


On my Linux Ubuntu 6.10 (kernel 2.6.17-10, Python 2.5) different type of errors are raised depending on the application (client or server).
In an asyncore-based client the error is raised by socket module (dispatcher's "self.socket" attribute) inside 'connect' method of 'dispatcher' class:

[...]
connections: 1018
connections: 1019
connections: 1020
connections: 1021
Traceback (most recent call last):
  File "asyncore_client.py", line 31, in <module>
  File "asyncore.py", line 191, in loop
  File "asyncore.py", line 138, in poll
  File "asyncore.py", line 80, in write
  File "asyncore.py", line 76, in write
  File "asyncore.py", line 395, in handle_write_event
  File "asyncore_client.py", line 24, in handle_connect
  File "asyncore_client.py", line 9, in __init__
  File "asyncore.py", line 257, in create_socket
  File "socket.py", line 156, in __init__
socket.error: (24, 'Too many open files')


On an asyncore-based server the error is raised by socket module (dispatcher's "self.socket" attribute) inside 'accept' method of 'dispatcher' class:

[...]
connections: 1019
connections: 1020
connections: 1021
Traceback (most recent call last):
  File "asyncore_server.py", line 38, in <module>
  File "asyncore.py", line 191, in loop
  File "asyncore.py", line 132, in poll
  File "asyncore.py", line 72, in read
  File "asyncore.py", line 68, in read
  File "asyncore.py", line 384, in handle_read_event
  File "asyncore_server.py", line 16, in handle_accept
  File "asyncore.py", line 321, in accept
  File "socket.py", line 170, in accept
socket.error: (24, 'Too many open files')


----------------------------------------------------------------------

Comment By: Sam Rushing (rushing)
Date: 2007-03-30 10:22

Message:
Logged In: YES 
user_id=73736
Originator: NO

Turns out medusa doesn't have a socket counter class, that was some other
project I was thinking of.

Putting a try/except in place doesn't really help the problem... if you
fail to create a new socket what action will you take?

A better approach is to have a configurable limit on the number of open
connections, and then have a server-specific reaction to exceeding that
limit.  For example, an SMTP server might respond with a 4XX greeting and
close the connection.

An additional problem on Unix is that running out of descriptors affects
more than just sockets.  Once you hit the FD limit you can't open files,
or do anything that requires a descriptor.


----------------------------------------------------------------------

Comment By: billiejoex (billiejoex)
Date: 2007-03-29 07:03

Message:
Logged In: YES 
user_id=1357589
Originator: YES

> The problem is that there's no portable way to know what the limit
> on file descriptors is.

Why don't put a try/except statement before creating a new socket's
file-descriptor?
I believe that such problem shouldn't be understimated. 
Actually asyncore is the only asynchronous module present in Python's
stdlib.
If asyncore suffers a DoS vulnerability it just means that writing a
secure client/server application with Python without using a third-party
library isn't possible.

I wrote a modified version of asyncore that solves the problem with select
 (affecting Windows) but still can't find a way to solve the problem with
socket's file-descriptors (affecting Unix).

----------------------------------------------------------------------

Comment By: Sam Rushing (rushing)
Date: 2007-03-23 12:59

Message:
Logged In: YES 
user_id=73736
Originator: NO

The problem is that there's no portable way to know what the limit
on file descriptors is.  The 'classic' for select/poll is the FD_SETSIZE
macro.  But on some operating systems there is no such limit. [e.g.,
win32
does not use the 'lowest-free-int' model common to unix].

I believe that in Medusa there was a derived class or extension that
counted
the number of open sockets, and limited it, using something like a
semaphore.


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1685000&group_id=5470


More information about the Python-bugs-list mailing list