aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorHowJMay <vulxj0j8j8@gmail.com>2021-04-19 18:06:54 +0000
committerIan Lance Taylor <iant@golang.org>2021-04-19 21:27:43 +0000
commite97d8eb027c0067f757860b6f766644de15941f2 (patch)
tree0293d4cafe26127f9563f56a8e11bbe1554046c0 /src/net
parentbbb510ccc96e2ca1d0d1c91d244fba4e735d5a80 (diff)
downloadgo-e97d8eb027c0067f757860b6f766644de15941f2.tar.gz
go-e97d8eb027c0067f757860b6f766644de15941f2.zip
net: pass MSG_CMSG_CLOEXEC flag in ReadMsgUnix
As mentioned in #42765, calling "recvmsg" syscall on Linux should come with "MSG_CMSG_CLOEXEC" flag. For other systems which not supports "MSG_CMSG_CLOEXEC". ReadMsgUnix() would check the header. If the header type is "syscall.SCM_RIGHTS", then ReadMsgUnix() would parse the SocketControlMessage and call each fd with "syscall.CloseOnExec" Fixes #42765 Change-Id: I74347db72b465685d7684bf0f32415d285845ebb GitHub-Last-Rev: ca59e2c9e0e8de1ae590e9b6dc165cb768a574f5 GitHub-Pull-Request: golang/go#42768 Reviewed-on: https://go-review.googlesource.com/c/go/+/272226 Trust: Emmanuel Odeke <emmanuel@orijtech.com> Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/fd_posix.go6
-rw-r--r--src/net/iprawsock_posix.go2
-rw-r--r--src/net/net_fake.go2
-rw-r--r--src/net/udpsock_posix.go2
-rw-r--r--src/net/unixsock_posix.go6
-rw-r--r--src/net/unixsock_readmsg_linux.go17
-rw-r--r--src/net/unixsock_readmsg_other.go13
-rw-r--r--src/net/unixsock_readmsg_posix.go33
-rw-r--r--src/net/unixsock_readmsg_test.go105
9 files changed, 179 insertions, 7 deletions
diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go
index 2945e46a48..4703ff33a1 100644
--- a/src/net/fd_posix.go
+++ b/src/net/fd_posix.go
@@ -64,10 +64,10 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return n, sa, wrapSyscallError(readFromSyscallName, err)
}
-func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
- n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
+func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
+ n, oobn, retflags, sa, err = fd.pfd.ReadMsg(p, oob, flags)
runtime.KeepAlive(fd)
- return n, oobn, flags, sa, wrapSyscallError(readMsgSyscallName, err)
+ return n, oobn, retflags, sa, wrapSyscallError(readMsgSyscallName, err)
}
func (fd *netFD) Write(p []byte) (nn int, err error) {
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index c1514f1698..b94eec0e18 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -75,7 +75,7 @@ func stripIPv4Header(n int, b []byte) int {
func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{IP: sa.Addr[0:]}
diff --git a/src/net/net_fake.go b/src/net/net_fake.go
index 49dc57c6ff..74fc1da6fd 100644
--- a/src/net/net_fake.go
+++ b/src/net/net_fake.go
@@ -268,7 +268,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return 0, nil, syscall.ENOSYS
}
-func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
return 0, 0, 0, nil, syscall.ENOSYS
}
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 3b5346e573..fcfb9c004c 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -56,7 +56,7 @@ func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index 1d1f27449f..0306b5989b 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -113,7 +113,11 @@ func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob, readMsgFlags)
+ if oobn > 0 {
+ setReadMsgCloseOnExec(oob[:oobn])
+ }
+
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
diff --git a/src/net/unixsock_readmsg_linux.go b/src/net/unixsock_readmsg_linux.go
new file mode 100644
index 0000000000..3296681017
--- /dev/null
+++ b/src/net/unixsock_readmsg_linux.go
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+// +build linux
+
+package net
+
+import (
+ "syscall"
+)
+
+const readMsgFlags = syscall.MSG_CMSG_CLOEXEC
+
+func setReadMsgCloseOnExec(oob []byte) {
+}
diff --git a/src/net/unixsock_readmsg_other.go b/src/net/unixsock_readmsg_other.go
new file mode 100644
index 0000000000..c8db657cd6
--- /dev/null
+++ b/src/net/unixsock_readmsg_other.go
@@ -0,0 +1,13 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (js && wasm) || windows
+// +build js,wasm windows
+
+package net
+
+const readMsgFlags = 0
+
+func setReadMsgCloseOnExec(oob []byte) {
+}
diff --git a/src/net/unixsock_readmsg_posix.go b/src/net/unixsock_readmsg_posix.go
new file mode 100644
index 0000000000..07d7df5e66
--- /dev/null
+++ b/src/net/unixsock_readmsg_posix.go
@@ -0,0 +1,33 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris
+// +build aix darwin dragonfly freebsd netbsd openbsd solaris
+
+package net
+
+import (
+ "syscall"
+)
+
+const readMsgFlags = 0
+
+func setReadMsgCloseOnExec(oob []byte) {
+ scms, err := syscall.ParseSocketControlMessage(oob)
+ if err != nil {
+ return
+ }
+
+ for _, scm := range scms {
+ if scm.Header.Level == syscall.SOL_SOCKET && scm.Header.Type == syscall.SCM_RIGHTS {
+ fds, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ continue
+ }
+ for _, fd := range fds {
+ syscall.CloseOnExec(fd)
+ }
+ }
+ }
+}
diff --git a/src/net/unixsock_readmsg_test.go b/src/net/unixsock_readmsg_test.go
new file mode 100644
index 0000000000..4961ecbe10
--- /dev/null
+++ b/src/net/unixsock_readmsg_test.go
@@ -0,0 +1,105 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func TestUnixConnReadMsgUnixSCMRightsCloseOnExec(t *testing.T) {
+ if !testableNetwork("unix") {
+ t.Skip("not unix system")
+ }
+
+ scmFile, err := os.Open(os.DevNull)
+ if err != nil {
+ t.Fatalf("file open: %v", err)
+ }
+ defer scmFile.Close()
+
+ rights := syscall.UnixRights(int(scmFile.Fd()))
+ fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
+ if err != nil {
+ t.Fatalf("Socketpair: %v", err)
+ }
+
+ writeFile := os.NewFile(uintptr(fds[0]), "write-socket")
+ defer writeFile.Close()
+ readFile := os.NewFile(uintptr(fds[1]), "read-socket")
+ defer readFile.Close()
+
+ cw, err := FileConn(writeFile)
+ if err != nil {
+ t.Fatalf("FileConn: %v", err)
+ }
+ defer cw.Close()
+ cr, err := FileConn(readFile)
+ if err != nil {
+ t.Fatalf("FileConn: %v", err)
+ }
+ defer cr.Close()
+
+ ucw, ok := cw.(*UnixConn)
+ if !ok {
+ t.Fatalf("got %T; want UnixConn", cw)
+ }
+ ucr, ok := cr.(*UnixConn)
+ if !ok {
+ t.Fatalf("got %T; want UnixConn", cr)
+ }
+
+ oob := make([]byte, syscall.CmsgSpace(4))
+ err = ucw.SetWriteDeadline(time.Now().Add(5 * time.Second))
+ if err != nil {
+ t.Fatalf("Can't set unix connection timeout: %v", err)
+ }
+ _, _, err = ucw.WriteMsgUnix(nil, rights, nil)
+ if err != nil {
+ t.Fatalf("UnixConn readMsg: %v", err)
+ }
+ err = ucr.SetReadDeadline(time.Now().Add(5 * time.Second))
+ if err != nil {
+ t.Fatalf("Can't set unix connection timeout: %v", err)
+ }
+ _, oobn, _, _, err := ucr.ReadMsgUnix(nil, oob)
+ if err != nil {
+ t.Fatalf("UnixConn readMsg: %v", err)
+ }
+
+ scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ t.Fatalf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != 1 {
+ t.Fatalf("got scms = %#v; expected 1 SocketControlMessage", scms)
+ }
+ scm := scms[0]
+ gotFds, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ t.Fatalf("syscall.ParseUnixRights: %v", err)
+ }
+ if len(gotFds) != 1 {
+ t.Fatalf("got FDs %#v: wanted only 1 fd", gotFds)
+ }
+ defer func() {
+ if err := syscall.Close(int(gotFds[0])); err != nil {
+ t.Fatalf("fail to close gotFds: %v", err)
+ }
+ }()
+
+ flags, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(gotFds[0]), uintptr(syscall.F_GETFD), 0)
+ if errno != 0 {
+ t.Fatalf("Can't get flags of fd:%#v, with err:%v", gotFds[0], errno)
+ }
+ if flags&syscall.FD_CLOEXEC == 0 {
+ t.Fatalf("got flags %#x, want %#x (FD_CLOEXEC) set", flags, syscall.FD_CLOEXEC)
+ }
+}