[gnutls-devel] GnuTLS | WIP: fixed operation under multiple threads (!935)

Development of GNU's TLS library gnutls-devel at lists.gnutls.org
Mon Feb 25 17:50:38 CET 2019


Hugo Beauzée-Luyssen commented on a discussion on lib/record.c:

>  		 * data. We allow sending however, if we are in false start handshake
>  		 * state. */
>  		if (session->internals.recv_state != RECV_STATE_FALSE_START &&
> +		    session->internals.recv_state != RECV_STATE_FALSE_START_HANDLING &&
>  		    session->internals.recv_state != RECV_STATE_EARLY_START &&
> -		    !(session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT))
> -			return gnutls_assert_val(GNUTLS_E_UNAVAILABLE_DURING_HANDSHAKE);
> +		    session->internals.recv_state != RECV_STATE_EARLY_START_HANDLING &&
> +		    !(session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT)) {
> +			/* this additional check is to avoid a mutex for applications sending
> +			 * and receiving in parallel. */
> +			if (!session->internals.initial_negotiation_completed)

If you can get away with waiting for the negotiation to complete, maybe an atomic variable for the `initial_negotiation_completed` flag & a semaphore to delay a call to recv while send is completing the handshake, or the other way around?

If the values of `recv_state` & `initial_negotiation_completed` are dependent on each other, I'm not sure you can go away without a mutex though. If `recv_state` doesn't change after the initial call to `gnutls_handshake` then the checks above will work fine.

AFAICS `initial_negotiation_completed` will be updated from a subsequent call to recv/send, so you need to synchronize read/writes to it. If that value doesn't need to be updated based on recv_state, an atomic variable is enough, but it seems the sequence goes something like this:
```
recv_handshake_final()
{
   switch ( final_state )
   {
       //.....
       case STATE31:
            _gnutls_recv_finished() // initial_negotiation_completed = 1;
            final_state = STATE0;
   }
}
```
That kind of logic requires a lock IMO. Having `final_state` equal to `STATE31` at the begining of the switch doesn't mean it will still be equal to `STATE31` by the time `_gnutls_recv_finished` returns. The way I see it you need a lock to ensure that 2 racing threads would not perform the same steps simultaneously.

That being said, I do not know the GnuTLS sources enough (let alone TLS itself), and I might be completely missing the point, misunderstanding the call graph, [...], so please forgive me if some comments are completely out of touch with reality

-- 
Reply to this email directly or view it on GitLab: https://gitlab.com/gnutls/gnutls/merge_requests/935#note_144817381
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.gnupg.org/pipermail/gnutls-devel/attachments/20190225/4ac45ad9/attachment.html>


More information about the Gnutls-devel mailing list