diff options
author | Tamir Duberstein <tamird@google.com> | 2018-09-05 18:58:09 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-09-05 18:59:16 -0700 |
commit | 156b49ca85be7602ec034167767f0d0bfedf2be5 (patch) | |
tree | e1ab6c9664461f0641ca2641f3549481a316b35f /pkg | |
parent | 5f0002fc83a77a39d9a2ef1443bc6c18e22ea779 (diff) |
Fix race condition introduced in 211135505
Now that it's possible to remove subnets, we must iterate over them with locks
held.
Also do the removal more efficiently while I'm here.
PiperOrigin-RevId: 211737416
Change-Id: I29025ec8b0c3ad11f22d4447e8ad473f1c785463
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/tcpip/stack/nic.go | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index 7aa960096..845b40f11 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -266,11 +266,14 @@ func (n *NIC) AddSubnet(protocol tcpip.NetworkProtocolNumber, subnet tcpip.Subne func (n *NIC) RemoveSubnet(subnet tcpip.Subnet) { n.mu.Lock() - for i, sub := range n.subnets { - if sub == subnet { - n.subnets = append(n.subnets[:i], n.subnets[i+1:]...) + // Use the same underlying array. + tmp := n.subnets[:0] + for _, sub := range n.subnets { + if sub != subnet { + tmp = append(tmp, sub) } } + n.subnets = tmp n.mu.Unlock() } @@ -369,33 +372,34 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin id := NetworkEndpointID{dst} n.mu.RLock() - ref := n.endpoints[id] - if ref != nil && !ref.tryIncRef() { + ref, ok := n.endpoints[id] + if ok && !ref.tryIncRef() { ref = nil } - promiscuous := n.promiscuous - subnets := n.subnets - n.mu.RUnlock() - - if ref == nil { + if ref != nil { + n.mu.RUnlock() + } else { + promiscuous := n.promiscuous // Check if the packet is for a subnet this NIC cares about. if !promiscuous { - for _, sn := range subnets { + for _, sn := range n.subnets { if sn.Contains(dst) { promiscuous = true break } } } + n.mu.RUnlock() if promiscuous { // Try again with the lock in exclusive mode. If we still can't // get the endpoint, create a new "temporary" one. It will only // exist while there's a route through it. n.mu.Lock() - ref = n.endpoints[id] - if ref == nil || !ref.tryIncRef() { - ref, _ = n.addAddressLocked(protocol, dst, true) - if ref != nil { + ref, ok = n.endpoints[id] + if !ok || !ref.tryIncRef() { + var err *tcpip.Error + ref, err = n.addAddressLocked(protocol, dst, true) + if err == nil { ref.holdsInsertRef = false } } |