From ddfad453cf22146e9476a5f4b91cf6c47b77e9c7 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 27 Nov 2019 13:38:45 +0100 Subject: [PATCH] device: SendmsgN mutates the input sockaddr So we take a new granular lock to prevent concurrent writes from racing. WARNING: DATA RACE Write at 0x00c0011f2740 by goroutine 27: golang.org/x/sys/unix.(*SockaddrInet4).sockaddr() /go/pkg/mod/golang.org/x/sys@v0.0.0-20191105231009-c1f44814a5cd/unix/syscall_linux.go:384 +0x114 golang.org/x/sys/unix.SendmsgN() /go/pkg/mod/golang.org/x/sys@v0.0.0-20191105231009-c1f44814a5cd/unix/syscall_linux.go:1304 +0x288 golang.zx2c4.com/wireguard/device.send4() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/conn_linux.go:485 +0x11f golang.zx2c4.com/wireguard/device.(*nativeBind).Send() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/conn_linux.go:268 +0x1d6 golang.zx2c4.com/wireguard/device.(*Peer).SendBuffer() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/peer.go:151 +0x285 golang.zx2c4.com/wireguard/device.(*Peer).SendHandshakeInitiation() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/send.go:163 +0x692 golang.zx2c4.com/wireguard/device.(*Device).RoutineReadFromTUN() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/send.go:318 +0x4b8 Previous write at 0x00c0011f2740 by goroutine 386: golang.org/x/sys/unix.(*SockaddrInet4).sockaddr() /go/pkg/mod/golang.org/x/sys@v0.0.0-20191105231009-c1f44814a5cd/unix/syscall_linux.go:384 +0x114 golang.org/x/sys/unix.SendmsgN() /go/pkg/mod/golang.org/x/sys@v0.0.0-20191105231009-c1f44814a5cd/unix/syscall_linux.go:1304 +0x288 golang.zx2c4.com/wireguard/device.send4() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/conn_linux.go:485 +0x11f golang.zx2c4.com/wireguard/device.(*nativeBind).Send() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/conn_linux.go:268 +0x1d6 golang.zx2c4.com/wireguard/device.(*Peer).SendBuffer() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/peer.go:151 +0x285 golang.zx2c4.com/wireguard/device.(*Peer).SendHandshakeInitiation() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/send.go:163 +0x692 golang.zx2c4.com/wireguard/device.expiredRetransmitHandshake() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/timers.go:110 +0x40c golang.zx2c4.com/wireguard/device.(*Peer).NewTimer.func1() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/timers.go:42 +0xd8 Goroutine 27 (running) created at: golang.zx2c4.com/wireguard/device.NewDevice() /go/pkg/mod/golang.zx2c4.com/wireguard@v0.0.20191012/device/device.go:322 +0x5e8 main.main() /go/src/x/main.go:102 +0x58e Goroutine 386 (finished) created at: time.goFunc() /usr/local/go/src/time/sleep.go:168 +0x51 Reported-by: Ben Burkert --- device/conn_linux.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/device/conn_linux.go b/device/conn_linux.go index dafaf31..b38aa38 100644 --- a/device/conn_linux.go +++ b/device/conn_linux.go @@ -43,6 +43,7 @@ type IPv6Source struct { } type NativeEndpoint struct { + sync.Mutex dst [unsafe.Sizeof(unix.SockaddrInet6{})]byte src [unsafe.Sizeof(IPv6Source{})]byte isV6 bool @@ -482,7 +483,9 @@ func send4(sock int, end *NativeEndpoint, buff []byte) error { }, } + end.Lock() _, err := unix.SendmsgN(sock, buff, (*[unsafe.Sizeof(cmsg)]byte)(unsafe.Pointer(&cmsg))[:], end.dst4(), 0) + end.Unlock() if err == nil { return nil @@ -493,7 +496,9 @@ func send4(sock int, end *NativeEndpoint, buff []byte) error { if err == unix.EINVAL { end.ClearSrc() cmsg.pktinfo = unix.Inet4Pktinfo{} + end.Lock() _, err = unix.SendmsgN(sock, buff, (*[unsafe.Sizeof(cmsg)]byte)(unsafe.Pointer(&cmsg))[:], end.dst4(), 0) + end.Unlock() } return err @@ -522,7 +527,9 @@ func send6(sock int, end *NativeEndpoint, buff []byte) error { cmsg.pktinfo.Ifindex = 0 } + end.Lock() _, err := unix.SendmsgN(sock, buff, (*[unsafe.Sizeof(cmsg)]byte)(unsafe.Pointer(&cmsg))[:], end.dst6(), 0) + end.Unlock() if err == nil { return nil @@ -533,7 +540,9 @@ func send6(sock int, end *NativeEndpoint, buff []byte) error { if err == unix.EINVAL { end.ClearSrc() cmsg.pktinfo = unix.Inet6Pktinfo{} + end.Lock() _, err = unix.SendmsgN(sock, buff, (*[unsafe.Sizeof(cmsg)]byte)(unsafe.Pointer(&cmsg))[:], end.dst6(), 0) + end.Unlock() } return err