tun: fix data race on name field

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2020-02-28 09:10:16 -08:00 committed by Jason A. Donenfeld
parent abd287159e
commit 85a45a9651

View file

@ -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
}