aboutsummaryrefslogtreecommitdiffstats
path: root/tun
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2021-04-26 22:22:45 -0400
committerJason A. Donenfeld <Jason@zx2c4.com>2021-04-26 22:22:45 -0400
commit097af6e1351ba80a18b8f63e9c07b9bd13b632bb (patch)
tree71053b525918fdf2fcde1793bb9e5986260050a9 /tun
parentconn: windows: do not error out when receiving UDP jumbogram (diff)
downloadwireguard-go-097af6e1351ba80a18b8f63e9c07b9bd13b632bb.tar.xz
wireguard-go-097af6e1351ba80a18b8f63e9c07b9bd13b632bb.zip
tun: windows: protect reads from closing
The code previously used the old errors channel for checking, rather than the simpler boolean, which caused issues on shutdown, since the errors channel was meaningless. However, looking at this exposed a more basic problem: Close() and all the other functions that check the closed boolean can race. So protect with a basic RW lock, to ensure that Close() waits for all pending operations to complete. Reported-by: Joshua Sjoding <joshua.sjoding@scjalliance.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'tun')
-rw-r--r--tun/tun_windows.go25
1 files changed, 19 insertions, 6 deletions
diff --git a/tun/tun_windows.go b/tun/tun_windows.go
index 9d83db7..c8b8d39 100644
--- a/tun/tun_windows.go
+++ b/tun/tun_windows.go
@@ -37,8 +37,8 @@ type NativeTun struct {
wt *wintun.Adapter
handle windows.Handle
close bool
+ closing sync.RWMutex
events chan Event
- errors chan error
forcedMTU int
rate rateJuggler
session wintun.Session
@@ -97,7 +97,6 @@ func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID, mtu
wt: wt,
handle: windows.InvalidHandle,
events: make(chan Event, 10),
- errors: make(chan error, 1),
forcedMTU: forcedMTU,
}
@@ -112,6 +111,11 @@ func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID, mtu
}
func (tun *NativeTun) Name() (string, error) {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
+ if tun.close {
+ return "", os.ErrClosed
+ }
return tun.wt.Name()
}
@@ -126,6 +130,8 @@ func (tun *NativeTun) Events() chan Event {
func (tun *NativeTun) Close() error {
var err error
tun.closeOnce.Do(func() {
+ tun.closing.Lock()
+ defer tun.closing.Unlock()
tun.close = true
tun.session.End()
if tun.wt != nil {
@@ -148,11 +154,11 @@ func (tun *NativeTun) ForceMTU(mtu int) {
// Note: Read() and Write() assume the caller comes only from a single thread; there's no locking.
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
retry:
- select {
- case err := <-tun.errors:
- return 0, err
- default:
+ if tun.close {
+ return 0, os.ErrClosed
}
start := nanotime()
shouldSpin := atomic.LoadUint64(&tun.rate.current) >= spinloopRateThreshold && uint64(start-atomic.LoadInt64(&tun.rate.nextStartTime)) <= rateMeasurementGranularity*2
@@ -189,6 +195,8 @@ func (tun *NativeTun) Flush() error {
}
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
if tun.close {
return 0, os.ErrClosed
}
@@ -213,6 +221,11 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
// LUID returns Windows interface instance ID.
func (tun *NativeTun) LUID() uint64 {
+ tun.closing.RLock()
+ defer tun.closing.RUnlock()
+ if tun.close {
+ return 0
+ }
return tun.wt.LUID()
}