From 1a2b02849ce11fb4342a7da105df8b1b1d015e85 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 29 Apr 2025 11:49:51 -0700 Subject: [PATCH] ipn/ipnlocal: pass along localNodeContext lock state in context Fixes #15824 Change-Id: I0a85fda892ee34513a5d1b45ac47202e717f45c1 Signed-off-by: Brad Fitzpatrick --- ipn/ipnlocal/drive.go | 3 ++- ipn/ipnlocal/local.go | 17 ++++++++++++----- ipn/ipnlocal/taildrop.go | 6 +++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ipn/ipnlocal/drive.go b/ipn/ipnlocal/drive.go index f13c9de48..571877157 100644 --- a/ipn/ipnlocal/drive.go +++ b/ipn/ipnlocal/drive.go @@ -4,6 +4,7 @@ package ipnlocal import ( + "context" "fmt" "os" "slices" @@ -338,7 +339,7 @@ func (b *LocalBackend) driveRemotesFromPeers(nm *netmap.NetworkMap) []*drive.Rem // Check that the peer is allowed to share with us. addresses := peer.Addresses() for _, p := range addresses.All() { - if cn.PeerHasCap(p.Addr(), tailcfg.PeerCapabilityTaildriveSharer) { + if cn.PeerHasCap(context.Background(), p.Addr(), tailcfg.PeerCapabilityTaildriveSharer) { return true } } diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 95fe22641..f2f311edc 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -96,6 +96,7 @@ import ( "tailscale.com/types/ptr" "tailscale.com/types/views" "tailscale.com/util/clientmetric" + "tailscale.com/util/ctxkey" "tailscale.com/util/deephash" "tailscale.com/util/dnsname" "tailscale.com/util/goroutines" @@ -1463,7 +1464,11 @@ func (b *LocalBackend) PeerCaps(src netip.Addr) tailcfg.PeerCapMap { return b.currentNode().PeerCaps(src) } -func (b *localNodeContext) AppendMatchingPeers(base []tailcfg.NodeView, pred func(tailcfg.NodeView) bool) []tailcfg.NodeView { +var nodeCtxLockedKey = ctxkey.New("localNodeContext-locked", false) + +var ctxNodeContextLocked = nodeCtxLockedKey.WithValue(context.Background(), true) + +func (b *localNodeContext) AppendMatchingPeers(base []tailcfg.NodeView, pred func(context.Context, tailcfg.NodeView) bool) []tailcfg.NodeView { b.mu.Lock() defer b.mu.Unlock() ret := base @@ -1471,7 +1476,7 @@ func (b *localNodeContext) AppendMatchingPeers(base []tailcfg.NodeView, pred fun return ret } for _, peer := range b.netMap.Peers { - if pred(peer) { + if pred(ctxNodeContextLocked, peer) { ret = append(ret, peer) } } @@ -6652,9 +6657,11 @@ func (b *LocalBackend) TestOnlyPublicKeys() (machineKey key.MachinePublic, nodeK // PeerHasCap reports whether the peer with the given Tailscale IP addresses // contains the given capability string, with any value(s). -func (b *localNodeContext) PeerHasCap(addr netip.Addr, wantCap tailcfg.PeerCapability) bool { - b.mu.Lock() - defer b.mu.Unlock() +func (b *localNodeContext) PeerHasCap(ctx context.Context, addr netip.Addr, wantCap tailcfg.PeerCapability) bool { + if !nodeCtxLockedKey.Value(ctx) { + b.mu.Lock() + defer b.mu.Unlock() + } return b.peerHasCapLocked(addr, wantCap) } diff --git a/ipn/ipnlocal/taildrop.go b/ipn/ipnlocal/taildrop.go index 17ca40926..1dce8d0d8 100644 --- a/ipn/ipnlocal/taildrop.go +++ b/ipn/ipnlocal/taildrop.go @@ -190,14 +190,14 @@ func (b *LocalBackend) FileTargets() ([]*apitype.FileTarget, error) { if !b.capFileSharing { return nil, errors.New("file sharing not enabled by Tailscale admin") } - peers := cn.AppendMatchingPeers(nil, func(p tailcfg.NodeView) bool { + peers := cn.AppendMatchingPeers(nil, func(ctx context.Context, p tailcfg.NodeView) bool { if !p.Valid() || p.Hostinfo().OS() == "tvOS" { return false } if self != p.User() { return false } - if p.Addresses().Len() != 0 && cn.PeerHasCap(p.Addresses().At(0).Addr(), tailcfg.PeerCapabilityFileSharingTarget) { + if p.Addresses().Len() != 0 && cn.PeerHasCap(ctx, p.Addresses().At(0).Addr(), tailcfg.PeerCapabilityFileSharingTarget) { // Explicitly noted in the netmap ACL caps as a target. return true } @@ -241,7 +241,7 @@ func (b *LocalBackend) taildropTargetStatus(p tailcfg.NodeView) ipnstate.Taildro } if nm.User() != p.User() { // Different user must have the explicit file sharing target capability - if p.Addresses().Len() == 0 || !cn.PeerHasCap(p.Addresses().At(0).Addr(), tailcfg.PeerCapabilityFileSharingTarget) { + if p.Addresses().Len() == 0 || !cn.PeerHasCap(context.Background(), p.Addresses().At(0).Addr(), tailcfg.PeerCapabilityFileSharingTarget) { // Explicitly noted in the netmap ACL caps as a target. return ipnstate.TaildropTargetOwnedByOtherUser }