summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2020-02-28 09:10:16 -0800
committerJason A. Donenfeld <Jason@zx2c4.com>2020-05-02 01:46:42 -0600
commit85a45a9651d2b38e3616a7899800601656cf143e (patch)
tree6300314437c01d93d2ffa0665e4bd63e278e6570
parentabd287159e7eb7d20ee46c03d1a8cb9a645735e4 (diff)
tun: fix data race on name field
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
-rw-r--r--tun/tun_linux.go44
1 files 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
}