From 1cd4e11b26e86649cf98d7dfb417da39541cb6b3 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 (cherry picked from commit ecfb2639cc3a50510d54335d22dc1e3584afcf8a) --- ipn/ipnlocal/local.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index bf997023f..a793497a8 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1890,6 +1890,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 {