aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Adler <colin1adler@gmail.com>2023-08-08 23:29:54 +0000
committerJason A. Donenfeld <Jason@zx2c4.com>2025-05-04 18:11:00 +0200
commitda97097e22096deb17bb3486f3ab205b4c5b4cdb (patch)
treee864078d84ee074876d9c6acddf38f8c89d3cd38
parentdevice: fix missed return of QueueOutboundElementsContainer to its WaitPool (diff)
downloadwireguard-go-da97097e22096deb17bb3486f3ab205b4c5b4cdb.tar.xz
wireguard-go-da97097e22096deb17bb3486f3ab205b4c5b4cdb.zip
tun/netstack: fix race during `(*netTun).Close()`
During `Close()`, it's possible for `WriteNotify()` to race a channel send with the channel close. See the race below: ``` ================== WARNING: DATA RACE Write at 0x00c000055450 by goroutine 18: runtime.closechan() /opt/hostedtoolcache/go/1.20.7/x64/src/runtime/chan.go:357 +0x0 golang.zx2c4.com/wireguard/tun/netstack.(*netTun).Close() /home/runner/go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.0-20230325221338-052af4a8072b/tun/netstack/tun.go:178 +0xde golang.zx2c4.com/wireguard/device.(*Device).Close() /home/runner/go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.0-20230325221338-052af4a8072b/device/device.go:379 +0x181 github.com/coder/wgtunnel/tunneld.(*API).Close() /home/runner/go/pkg/mod/github.com/coder/wgtunnel@v0.1.5/tunneld/tunneld.go:78 +0x64 github.com/coder/coder/coderd/devtunnel_test.newTunnelServer.func2() /home/runner/actions-runner/_work/coder/coder/coderd/devtunnel/tunnel_test.go:211 +0x30 testing.(*common).Cleanup.func1() /opt/hostedtoolcache/go/1.20.7/x64/src/testing/testing.go:1150 +0x193 testing.(*common).runCleanup() /opt/hostedtoolcache/go/1.20.7/x64/src/testing/testing.go:1328 +0x1e9 testing.tRunner.func2() /opt/hostedtoolcache/go/1.20.7/x64/src/testing/testing.go:1570 +0x52 runtime.deferreturn() /opt/hostedtoolcache/go/1.20.7/x64/src/runtime/panic.go:476 +0x32 testing.(*T).Run.func1() /opt/hostedtoolcache/go/1.20.7/x64/src/testing/testing.go:1629 +0x47 Previous read at 0x00c000055450 by goroutine 244: runtime.chansend() /opt/hostedtoolcache/go/1.20.7/x64/src/runtime/chan.go:160 +0x0 golang.zx2c4.com/wireguard/tun/netstack.(*netTun).WriteNotify() /home/runner/go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.0-20230325221338-052af4a8072b/tun/netstack/tun.go:165 +0xe6 gvisor.dev/gvisor/pkg/tcpip/link/channel.(*queue).Write() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/link/channel/channel.go:100 +0x183 gvisor.dev/gvisor/pkg/tcpip/link/channel.(*Endpoint).WritePackets() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/link/channel/channel.go:258 +0xb7 gvisor.dev/gvisor/pkg/tcpip/stack.(*delegatingQueueingDiscipline).WritePacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/stack/nic.go:146 +0x97 gvisor.dev/gvisor/pkg/tcpip/stack.(*nic).writeRawPacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/stack/nic.go:392 +0x84 gvisor.dev/gvisor/pkg/tcpip/stack.(*nic).writePacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/stack/nic.go:386 +0x59 gvisor.dev/gvisor/pkg/tcpip/stack.(*nic).WritePacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/stack/nic.go:347 +0x22b gvisor.dev/gvisor/pkg/tcpip/network/ipv6.(*endpoint).writePacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/network/ipv6/ipv6.go:878 +0x408 gvisor.dev/gvisor/pkg/tcpip/network/ipv6.(*endpoint).WritePacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/network/ipv6/ipv6.go:829 +0x2d7 gvisor.dev/gvisor/pkg/tcpip/stack.(*Route).WritePacket() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/stack/route.go:495 +0xf8 gvisor.dev/gvisor/pkg/tcpip/transport/tcp.sendTCP() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/connect.go:918 +0x3fb gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*endpoint).sendTCP() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/connect.go:816 +0x199 gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*endpoint).sendRaw() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/connect.go:985 +0x53a gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*sender).sendSegmentFromPacketBuffer() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/snd.go:1686 +0x26d gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*sender).sendSegment() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/snd.go:1647 +0x386 gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*sender).maybeSendSegment() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/snd.go:877 +0x704 gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*sender).sendData() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/snd.go:981 +0x4fa gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*endpoint).sendData() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/connect.go:1009 +0xc4 gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*endpoint).shutdownLocked() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/endpoint.go:2536 +0x44f gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*endpoint).closeLocked() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/endpoint.go:1063 +0xa9 gvisor.dev/gvisor/pkg/tcpip/transport/tcp.(*endpoint).Close() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/transport/tcp/endpoint.go:1033 +0x5d gvisor.dev/gvisor/pkg/tcpip/adapters/gonet.(*TCPConn).Close() /home/runner/go/pkg/mod/github.com/coder/gvisor@v0.0.0-20230714132058-be2e4ac102c3/pkg/tcpip/adapters/gonet/gonet.go:417 +0x4a github.com/coder/wgtunnel/tunneld.(*tracingConnWrapper).Close() /home/runner/go/pkg/mod/github.com/coder/wgtunnel@v0.1.5/tunneld/tracing.go:39 +0x7d net/http.(*persistConn).closeLocked() /opt/hostedtoolcache/go/1.20.7/x64/src/net/http/transport.go:2732 +0x222 net/http.(*persistConn).readLoopPeekFailLocked() /opt/hostedtoolcache/go/1.20.7/x64/src/net/http/transport.go:2267 +0x344 net/http.(*persistConn).readLoop() /opt/hostedtoolcache/go/1.20.7/x64/src/net/http/transport.go:2111 +0x1029 net/http.(*Transport).dialConn.func5() /opt/hostedtoolcache/go/1.20.7/x64/src/net/http/transport.go:1765 +0x39 ``` Signed-off-by: Colin Adler <colin1adler@gmail.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--tun/netstack/tun.go20
1 files changed, 15 insertions, 5 deletions
diff --git a/tun/netstack/tun.go b/tun/netstack/tun.go
index 2b73054..5229319 100644
--- a/tun/netstack/tun.go
+++ b/tun/netstack/tun.go
@@ -19,6 +19,7 @@ import (
"regexp"
"strconv"
"strings"
+ "sync"
"syscall"
"time"
@@ -42,7 +43,10 @@ import (
type netTun struct {
ep *channel.Endpoint
stack *stack.Stack
+ notifyHandle *channel.NotificationHandle
events chan tun.Event
+ pktMu sync.RWMutex
+ pktClosed bool
incomingPacket chan *buffer.View
mtu int
dnsServers []netip.Addr
@@ -70,7 +74,7 @@ func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device,
if tcpipErr != nil {
return nil, nil, fmt.Errorf("could not enable TCP SACK: %v", tcpipErr)
}
- dev.ep.AddNotify(dev)
+ dev.notifyHandle = dev.ep.AddNotify(dev)
tcpipErr = dev.stack.CreateNIC(1, dev.ep)
if tcpipErr != nil {
return nil, nil, fmt.Errorf("CreateNIC: %v", tcpipErr)
@@ -162,11 +166,16 @@ func (tun *netTun) WriteNotify() {
view := pkt.ToView()
pkt.DecRef()
- tun.incomingPacket <- view
+ tun.pktMu.RLock()
+ if !tun.pktClosed {
+ tun.incomingPacket <- view
+ }
+ tun.pktMu.RUnlock()
}
func (tun *netTun) Close() error {
tun.stack.RemoveNIC(1)
+ tun.ep.RemoveNotify(tun.notifyHandle)
if tun.events != nil {
close(tun.events)
@@ -174,9 +183,10 @@ func (tun *netTun) Close() error {
tun.ep.Close()
- if tun.incomingPacket != nil {
- close(tun.incomingPacket)
- }
+ tun.pktMu.Lock()
+ tun.pktClosed = true
+ close(tun.incomingPacket)
+ tun.pktMu.Unlock()
return nil
}