device: fix some lock ordering violations, add a test for a deadlock we hit
Discovered by a tool + test that will come in a future change. Updates tailscale/tailscale#19513 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
f69b24781e
commit
010dd5c6f2
3 changed files with 63 additions and 11 deletions
|
|
@ -348,17 +348,22 @@ func (device *Device) ConsumeMessageInitiation(msg *MessageInitiation, endpoint
|
|||
return nil
|
||||
}
|
||||
|
||||
// Snapshot staticIdentity so we don't hold the RLock across LookupPeer,
|
||||
// which may call NewPeer (reentrant RLock deadlocks against a pending
|
||||
// SetPrivateKey writer; see lock-ordering.md).
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
publicKey := device.staticIdentity.publicKey
|
||||
privateKey := device.staticIdentity.privateKey
|
||||
device.staticIdentity.RUnlock()
|
||||
|
||||
mixHash(&hash, &InitialHash, device.staticIdentity.publicKey[:])
|
||||
mixHash(&hash, &InitialHash, publicKey[:])
|
||||
mixHash(&hash, &hash, msg.Ephemeral[:])
|
||||
mixKey(&chainKey, &InitialChainKey, msg.Ephemeral[:])
|
||||
|
||||
// decrypt static key
|
||||
var peerPK NoisePublicKey
|
||||
var key [chacha20poly1305.KeySize]byte
|
||||
ss, err := device.staticIdentity.privateKey.sharedSecret(msg.Ephemeral)
|
||||
ss, err := privateKey.sharedSecret(msg.Ephemeral)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -533,6 +538,14 @@ func (device *Device) ConsumeMessageResponse(msg *MessageResponse) *Peer {
|
|||
chainKey [blake2s.Size]byte
|
||||
)
|
||||
|
||||
// Snapshot the static private key before acquiring handshake.mutex so
|
||||
// that handshake.mutex is never held while acquiring staticIdentity
|
||||
// (which would invert the staticIdentity < handshake.mutex hierarchy;
|
||||
// see lock-ordering.md).
|
||||
device.staticIdentity.RLock()
|
||||
privateKey := device.staticIdentity.privateKey
|
||||
device.staticIdentity.RUnlock()
|
||||
|
||||
ok := func() bool {
|
||||
// lock handshake state
|
||||
|
||||
|
|
@ -543,11 +556,6 @@ func (device *Device) ConsumeMessageResponse(msg *MessageResponse) *Peer {
|
|||
return false
|
||||
}
|
||||
|
||||
// lock private key for reading
|
||||
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
|
||||
// finish 3-way DH
|
||||
|
||||
mixHash(&hash, &handshake.hash, msg.Ephemeral[:])
|
||||
|
|
@ -560,7 +568,7 @@ func (device *Device) ConsumeMessageResponse(msg *MessageResponse) *Peer {
|
|||
mixKey(&chainKey, &chainKey, ss[:])
|
||||
setZero(ss[:])
|
||||
|
||||
ss, err = device.staticIdentity.privateKey.sharedSecret(msg.Ephemeral)
|
||||
ss, err = privateKey.sharedSecret(msg.Ephemeral)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue