]> Cypherpunks repositories - gostls13.git/commit
[release-branch.go1.7] crypto/tls: fix deadlock when racing to complete handshake.
authorAdam Langley <agl@golang.org>
Wed, 14 Sep 2016 18:50:36 +0000 (11:50 -0700)
committerChris Broadfoot <cbro@golang.org>
Mon, 17 Oct 2016 20:24:52 +0000 (20:24 +0000)
commitca0b97e80a558d06274e68ece667b821901acc42
tree5bfe3e9660bb024162333481220f6bb1ca410bb8
parent230c3918a8ae8a65e1974659e55f8a808fe731b5
[release-branch.go1.7] crypto/tls: fix deadlock when racing to complete handshake.

After renegotiation support was added (af125a5193c) it's possible for a
Write to block on a Read when racing to complete the handshake:
   1. The Write determines that a handshake is needed and tries to
      take the neccesary locks in the correct order.
   2. The Read also determines that a handshake is needed and wins
      the race to take the locks.
   3. The Read goroutine completes the handshake and wins a race
      to unlock and relock c.in, which it'll hold when waiting for
      more network data.

If the application-level protocol requires the Write to complete before
data can be read then the system as a whole will deadlock.

Unfortunately it doesn't appear possible to reverse the locking order of
c.in and handshakeMutex because we might read a renegotiation request at
any point and need to be able to do a handshake without unlocking.

So this change adds a sync.Cond that indicates that a goroutine has
committed to doing a handshake. Other interested goroutines can wait on
that Cond when needed.

The test for this isn't great. I was able to reproduce the deadlock with
it only when building with -race. (Because -race happened to alter the
timing just enough.)

Fixes #17101.

Change-Id: I4e8757f7b82a84e46c9963a977d089f0fb675495
Reviewed-on: https://go-review.googlesource.com/29164
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/31268
src/crypto/tls/conn.go
src/crypto/tls/handshake_client_test.go