From 85a45a9651d2b38e3616a7899800601656cf143e Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 28 Feb 2020 09:10:16 -0800 Subject: [PATCH] tun: fix data race on name field Signed-off-by: Brad Fitzpatrick --- tun/tun_linux.go | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/tun/tun_linux.go b/tun/tun_linux.go index 17b8822..2f97ebb 100644 --- a/tun/tun_linux.go +++ b/tun/tun_linux.go @@ -31,7 +31,6 @@ const ( type NativeTun struct { tunFile *os.File index int32 // if index - name string // name of interface errors chan error // async error handling events chan Event // device related events nopi bool // the device was passed IFF_NO_PI @@ -39,6 +38,10 @@ type NativeTun struct { netlinkCancel *rwcancel.RWCancel hackListenerClosed sync.Mutex statusListenersShutdown chan struct{} + + nameOnce sync.Once // guards calling initNameCache, which sets following fields + nameCache string // name of interface + nameErr error } func (tun *NativeTun) File() *os.File { @@ -192,6 +195,11 @@ func getIFIndex(name string) (int32, error) { } func (tun *NativeTun) setMTU(n int) error { + name, err := tun.Name() + if err != nil { + return err + } + // open datagram socket fd, err := unix.Socket( unix.AF_INET, @@ -206,9 +214,8 @@ func (tun *NativeTun) setMTU(n int) error { defer unix.Close(fd) // do ioctl call - var ifr [ifReqSize]byte - copy(ifr[:], tun.name) + copy(ifr[:], name) *(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n) _, _, errno := unix.Syscall( unix.SYS_IOCTL, @@ -225,6 +232,11 @@ func (tun *NativeTun) setMTU(n int) error { } func (tun *NativeTun) MTU() (int, error) { + name, err := tun.Name() + if err != nil { + return 0, err + } + // open datagram socket fd, err := unix.Socket( unix.AF_INET, @@ -241,7 +253,7 @@ func (tun *NativeTun) MTU() (int, error) { // do ioctl call var ifr [ifReqSize]byte - copy(ifr[:], tun.name) + copy(ifr[:], name) _, _, errno := unix.Syscall( unix.SYS_IOCTL, uintptr(fd), @@ -256,6 +268,15 @@ func (tun *NativeTun) MTU() (int, error) { } func (tun *NativeTun) Name() (string, error) { + tun.nameOnce.Do(tun.initNameCache) + return tun.nameCache, tun.nameErr +} + +func (tun *NativeTun) initNameCache() { + tun.nameCache, tun.nameErr = tun.nameSlow() +} + +func (tun *NativeTun) nameSlow() (string, error) { sysconn, err := tun.tunFile.SyscallConn() if err != nil { return "", err @@ -276,13 +297,11 @@ func (tun *NativeTun) Name() (string, error) { if errno != 0 { return "", errors.New("failed to get name of TUN device: " + errno.Error()) } - nullStr := ifr[:] - i := bytes.IndexByte(nullStr, 0) - if i != -1 { - nullStr = nullStr[:i] + name := ifr[:] + if i := bytes.IndexByte(name, 0); i != -1 { + name = name[:i] } - tun.name = string(nullStr) - return tun.name, nil + return string(name), nil } func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { @@ -402,16 +421,15 @@ func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { statusListenersShutdown: make(chan struct{}), nopi: false, } - var err error - _, err = tun.Name() + name, err := tun.Name() if err != nil { return nil, err } // start event listener - tun.index, err = getIFIndex(tun.name) + tun.index, err = getIFIndex(name) if err != nil { return nil, err }