• Adam Langley's avatar
    crypto/tls: fix deadlock when racing to complete handshake. · 254169d7
    Adam Langley authored
    After renegotiation support was added (af125a51) 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/29164Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
    Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
    254169d7
handshake_client_test.go 33.3 KB