Darryl Miles wrote:

> But this flag (while documented to the contrary) does nothing inside
> libssl.  So yes the documentation says you should set it, prove to me
> that OpenSSL behaves in a different way because you set it.

One of the biggest downsides of open source software is that encourages
people to code to what something happens to do rather than what it's
guaranteed to do.
 
> A hint to DS: grep the source tree of OpenSSL and follow all the
> code-paths determined by this flag to their conclusion.

Software development doesn't work that way. That's how you produce code that
suddenly fails mysteriously when you upgrade an unrelated component. The
first rule of software development is "thou shall not assume that something
that happens a particular way is guaranteed to do so, especially when the
documentation specifically warns that it is not".

> Now the next question you might want to ask, "is it allowed for 
> exactly two threads to operate specifically the SSL_read() and 
> SSL_write() on the _SAME_ 'SSL *' instance at the same time ?"  My 
> understanding would be that the answer is NO.   This is a limitation in 
> the OpenSSL library, since some of the shared parts of 'SSL *' have no 
> protection and the SSL_read() and SSL_write() code-paths have not been 
> audited/reworked to minimize the contention/data-race issues.

This is how everything else works, it's odd to say it's somehow a limitation
of OpenSSL that it works the same way everything else works. Try to read to
a string in one thread while you write to it from another. The general rule
of thread synchronization is that it is your responsibility to serialize
access to the same object from concurrent threads and the library's job to
synchronize accesses to distinct objects. OpenSSL follows this general rule.

Kernel objects are the exception, only because we cannot allow a program
(broken or valid) to screw up kernel objects. So the kernel has no choice
but to "overserialize".

> Your application then also has to evaluate its intent to send data, you 
> don't always have something more to send.  If you do then you need to 
> indicate to the OS to wake me up if I can push more data down into the 
> kernel buffer.

No, that is not how OpenSSL works. When you want to send data, you simply
call SSL_write. You only check if I/O is possible if OpenSSL specifically
tells you to. (OpenSSL may need to do something other than write to send the
data, for example, it may need to read renegotiation data.)

The other gotcha is that if you use separate read and write threads, you
*must* remember that an SSL connection only has one state. You cannot
independently maintain your own state in each thread, or you can deadlock.
This is a major cause of SSL deadlocks in "two thread" applications that run
their threads independently.

Here's the nightmare scenario:

1) You are in a point in the protocol where the other side will not send
anything unless we send something first. However, we try to read just in
case it sends something.

2) You call SSL_write from your write thread trying to send the data that
will keep the application protocol going, but a renegotiation is in progress
and no data has been received yet. You get WANT_READ.

(At this point, the SSL connection's one and only status is "want read to
send".)

2) The renegotiation data is received, but no application data is received.

3) You call SSL_read from your read thread (either just to try it, or
because you get a 'select' hit from the renegotiation data being received,
it doesn't matter. The OpenSSL library reads the renegotiation data, but no
application data is available. You get WANT_READ, since application data
needs to be received to make forward progress.

(At this point, the SSL connection's one and only status is "want read to
receive". Note that the read thread's actions *invalidate* the state the
write thread thinks it's in.)

4) Your write thread, having no idea that the read thread received a
different status, stupidly thinks it cannot make forward progress based on
the state it got from step 1 (since that's the last thing *it* did).
However, it *can* make forward progress (because another thread changed the
SSL state).

5) Now the other end is waiting for you to send data, and you are waiting to
receive the renegotiation data you already received.

You see, in step 4, the write thread *must* know that the read thread
changed the SSL connection's status. Otherwise you deadlock.

DS



______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to