Re: m2crypto blocking all other threads

Rune Froysa <[email protected]>
Newsgroups gmane.comp.python.cryptography
Message-ID <[email protected]>
Heikki Toivonen <[email protected]> writes:

> Rune Froysa wrote:
> > I'm using m2crypto for a SSL-based xmlrpc service.  This service is
> > frequently DOSed by what appears to be a bug in m2crypto: it blocks
> 
> It seems like this is user error. In a multithreaded application you
> need to initialize M2Crypto for threading. With those changes your
> sample works for me. See below:

Sorry about that.  Is this documented some place?  For some reason,
demo/ssl/https_srv.py works without it (two "openssl s_client -connect
localhost:19443" can connect simultaneously without problems).
However, a "telnet localhost 19443"+<do nothing> first will prevent
any later s_clients from reaching past the "CONNECTED(00000003)"
state.

The threading.init() trick seems to work for my previous example, but
if I add a threading.init() to line 135 (first in __main__) of
demo/ssl/https_srv.py, i get a segfault when a client connects (python
2.3.4) (It works if I actually have created a separate thread):

Starting program: /usr/bin/python https_srv.py
[Thread debugging using libthread_db enabled]
[New Thread -1208785216 (LWP 12122)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1208785216 (LWP 12122)]
0x00dbdb4a in sem_post@GLIBC_2.0 () from /lib/tls/libpthread.so.0
(gdb) where
#0  0x00dbdb4a in sem_post@GLIBC_2.0 () from /lib/tls/libpthread.so.0
#1  0x080cf636 in PyThread_release_lock (lock=0x0) at Python/thread_pthread.h:431
#2  0x080ca519 in PyGILState_Release (oldstate=3080343864) at Python/pystate.c:473
#3  0xb7ad39e8 in ssl_info_callback (s=0x81ef058, where=16, ret=1) at SWIG/_m2crypto.c:1058
#4  0x00b251e2 in ssl23_accept () from /lib/libssl.so.4
#5  0x00b2a093 in SSL_accept () from /lib/libssl.so.4
#6  0xb7ad73b3 in ssl_accept (ssl=0x81ef058) at SWIG/_m2crypto.c:3492
#7  0xb7ae2d23 in _wrap_ssl_accept (self=0x0, args=0xb79b310c) at SWIG/_m2crypto.c:11191
#8  0x080ed9b0 in PyCFunction_Call (func=0xb7b2218c, arg=0xb79b310c, kw=0x1) at Objects/methodobject.c:108
#9  0x080a4f67 in call_function (pp_stack=0xbfffee9c, oparg=135426480) at Python/ceval.c:3439
...

> > BTW: under 0.15, the https_srv.py complains from line 126 -> SSL/Context.py: 118:
> > TypeError: ssl_ctx_load_verify_locations() argument 3 must be string, not None
> 
> This does not happen for me.

Strange.  Latest version from svn:

/tmp/m2/demo/ssl@dresden >PYTHONPATH=/tmp/m2/build/lib.linux-i686-2.3 python https_srv.py 
Traceback (most recent call last):
  File "https_srv.py", line 141, in ?
    SSL.verify_none)
  File "https_srv.py", line 126, in init_context
    ctx.load_verify_info(cafile)
  File "/tmp/m2/build/lib.linux-i686-2.3/M2Crypto/SSL/Context.py", line 121, in load_verify_locations
    return m2.ssl_ctx_load_verify_locations(self.ctx, cafile, capath)
TypeError: ssl_ctx_load_verify_locations() argument 3 must be string, not None

It would be great if there was some way to set a timeout value on
connected clients.  With the below patch, https_srv.py could
instantiate the HTTPS_Server with a default_timeout=SSL.timeout(sec=4)
keyword argument to kill misbehaving clients (like the telnet above).
Could something like this be considered for future inclusion? (I don't
believe there is a standard pythonic way of setting timeout on client
sockets):

Index: M2Crypto/SSL/SSLServer.py
===================================================================
--- M2Crypto/SSL/SSLServer.py   (revision 319)
+++ M2Crypto/SSL/SSLServer.py   (working copy)
@@ -12,7 +12,7 @@
 
 
 class SSLServer(SocketServer.TCPServer):
-    def __init__(self, server_address, RequestHandlerClass, ssl_context):
+    def __init__(self, server_address, RequestHandlerClass, ssl_context, default_timeout=None):
         """ 
         Superclass says: Constructor. May be extended, do not override.
         This class says: Ho-hum.
@@ -21,6 +21,8 @@
         self.RequestHandlerClass=RequestHandlerClass
         self.ssl_ctx=ssl_context
         self.socket=Connection(self.ssl_ctx)
+        if default_timeout is not None:
+            self.socket.set_default_client_timeout(default_timeout)
         self.server_bind()
         self.server_activate()
 
Index: M2Crypto/SSL/Connection.py
===================================================================
--- M2Crypto/SSL/Connection.py  (revision 319)
+++ M2Crypto/SSL/Connection.py  (working copy)
@@ -38,6 +38,7 @@
             self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         self._fileno = self.socket.fileno()
+        self._default_client_timeout = None
         
     def __del__(self):
         if getattr(self, 'sslbio', None):
@@ -102,16 +103,27 @@
     def accept_ssl(self):
         return m2.ssl_accept(self.ssl)
 
+    def set_default_client_timeout(self, timeout):
+        self._default_client_timeout = timeout
+
     def accept(self):
         """Accept an SSL connection. The return value is a pair (ssl, addr) where
         ssl is a new SSL connection object and addr is the address bound to the
         the other end of the SSL connection."""
         sock, addr = self.socket.accept()
+        if self._default_client_timeout is not None:
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO,
+                            self._default_client_timeout.pack())
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, 
+                            self._default_client_timeout.pack())
+
         ssl = Connection(self.ctx, sock)
         ssl.addr = addr
         ssl.setup_ssl()
         ssl.set_accept_state()
-        ssl.accept_ssl()
+        if ssl.accept_ssl() != 1:
+            raise SSLError(m2.err_reason_error_string(m2.err_get_error()))
+        
         check = getattr(self, 'postConnectionCheck', self.serverPostConnectionCheck)
         if check is not None:
             if not check(self.get_peer_cert(), ssl.addr[0]):


Regards,
Rune Frøysa
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.