tun: avoid leaking sock fd in CreateTUN error cases

At these points, the socket file descriptor is not yet wrapped in an
*os.File, so it needs to be closed explicitly on error.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Tobias Klauser 2021-09-23 12:05:13 +02:00 committed by Jason A. Donenfeld
parent 2ef39d4754
commit eae5e0f3a3
2 changed files with 11 additions and 6 deletions

View file

@ -108,7 +108,6 @@ func CreateTUN(name string, mtu int) (Device, error) {
} }
fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2) fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -117,6 +116,7 @@ func CreateTUN(name string, mtu int) (Device, error) {
copy(ctlInfo.Name[:], []byte(utunControlName)) copy(ctlInfo.Name[:], []byte(utunControlName))
err = unix.IoctlCtlInfo(fd, ctlInfo) err = unix.IoctlCtlInfo(fd, ctlInfo)
if err != nil { if err != nil {
unix.Close(fd)
return nil, fmt.Errorf("IoctlGetCtlInfo: %w", err) return nil, fmt.Errorf("IoctlGetCtlInfo: %w", err)
} }
@ -127,11 +127,13 @@ func CreateTUN(name string, mtu int) (Device, error) {
err = unix.Connect(fd, sc) err = unix.Connect(fd, sc)
if err != nil { if err != nil {
unix.Close(fd)
return nil, err return nil, err
} }
err = syscall.SetNonblock(fd, true) err = unix.SetNonblock(fd, true)
if err != nil { if err != nil {
unix.Close(fd)
return nil, err return nil, err
} }
tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu) tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu)

View file

@ -419,6 +419,7 @@ func CreateTUN(name string, mtu int) (Device, error) {
var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack) var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack)
nameBytes := []byte(name) nameBytes := []byte(name)
if len(nameBytes) >= unix.IFNAMSIZ { if len(nameBytes) >= unix.IFNAMSIZ {
unix.Close(nfd)
return nil, fmt.Errorf("interface name too long: %w", unix.ENAMETOOLONG) return nil, fmt.Errorf("interface name too long: %w", unix.ENAMETOOLONG)
} }
copy(ifr[:], nameBytes) copy(ifr[:], nameBytes)
@ -431,17 +432,19 @@ func CreateTUN(name string, mtu int) (Device, error) {
uintptr(unsafe.Pointer(&ifr[0])), uintptr(unsafe.Pointer(&ifr[0])),
) )
if errno != 0 { if errno != 0 {
unix.Close(nfd)
return nil, errno return nil, errno
} }
err = unix.SetNonblock(nfd, true) err = unix.SetNonblock(nfd, true)
if err != nil {
unix.Close(nfd)
return nil, err
}
// Note that the above -- open,ioctl,nonblock -- must happen prior to handing it to netpoll as below this line. // Note that the above -- open,ioctl,nonblock -- must happen prior to handing it to netpoll as below this line.
fd := os.NewFile(uintptr(nfd), cloneDevicePath) fd := os.NewFile(uintptr(nfd), cloneDevicePath)
if err != nil {
return nil, err
}
return CreateTUNFromFile(fd, mtu) return CreateTUNFromFile(fd, mtu)
} }