From ecfb2639cc3a50510d54335d22dc1e3584afcf8a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 3 Jun 2021 09:39:30 -0700 Subject: [PATCH] ipn/ipnlocal: avoid initPeerAPIListener crash on certain concurrent actions We were crashing on in initPeerAPIListener when called from authReconfig when b.netMap is nil. But authReconfig already returns before the call to initPeerAPIListener when b.netMap is nil, but it releases the b.mu mutex before calling initPeerAPIListener which reacquires it and assumes it's still nil. The only thing that can be setting it to nil is setNetMapLocked, which is called by ResetForClientDisconnect, Logout/logout, or Start, all of which can happen during an authReconfig. So be more defensive. Fixes #1996 Signed-off-by: Brad Fitzpatrick --- ipn/ipnlocal/local.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index c4be19dd0..0ee5de1f9 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1888,6 +1888,15 @@ func (b *LocalBackend) initPeerAPIListener() { b.mu.Lock() defer b.mu.Unlock() + if b.netMap == nil { + // We're called from authReconfig which checks that + // netMap is non-nil, but if a concurrent Logout, + // ResetForClientDisconnect, or Start happens when its + // mutex was released, the netMap could be + // nil'ed out (Issue 1996). Bail out early here if so. + return + } + if len(b.netMap.Addresses) == len(b.peerAPIListeners) { allSame := true for i, pln := range b.peerAPIListeners {