-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/sys/unix: ParseSocketControlMessage error invalid argument #56384
Comments
Can you show us a complete standalone program that demonstrates the bug? Thanks. |
sure, I will provide it soon. |
example with nil payload in unix.Sendmsg and unix.Writeoutputwith
with
As you can see from the output in line codepackage main
import (
"fmt"
"os"
"os/exec"
"strconv"
"golang.org/x/sys/unix"
)
const dataPayload = "hello"
func main() {
if len(os.Args) > 2 && os.Args[1] == "child" {
pipeFd, err := strconv.Atoi(os.Args[2])
if err != nil {
panic(err)
}
child(pipeFd)
} else {
parent()
}
}
func parent() {
fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
if err != nil {
panic(err)
}
defer unix.Close(fds[0])
defer unix.Close(fds[1])
parentPipeFd := fds[0]
// set clo_exec flag on parent file descriptor
_, err = unix.FcntlInt(uintptr(parentPipeFd), unix.F_SETFD, unix.FD_CLOEXEC)
if err != nil {
panic(err)
}
cmd := exec.Command("/proc/self/exe", "child", strconv.Itoa(fds[1]))
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = cmd.Start(); err != nil {
panic(err)
}
// receive socket control message
b := make([]byte, unix.CmsgSpace(4))
_, _, _, _, err = unix.Recvmsg(parentPipeFd, nil, b, 0)
if err != nil {
panic(err)
}
fmt.Println("parent: recvmsg success")
data := make([]byte, len(dataPayload))
_, err = unix.Read(parentPipeFd, data)
if err != nil {
panic(err)
}
fmt.Printf("parent: read success [%s]\n", data)
// parse socket control message
cmsgs, err := unix.ParseSocketControlMessage(b)
if err != nil {
panic(err)
}
fmt.Println("parent: parseSocketControlMessage success")
receivedFds, err := unix.ParseUnixRights(&cmsgs[0])
if err != nil {
panic(err)
}
fmt.Println("parent: ParseUnixRights success")
receivedFd := receivedFds[0]
defer unix.Close(receivedFd)
fmt.Printf("parent: got fd %d\n", receivedFd)
if err = cmd.Wait(); err != nil {
panic(err)
}
}
func child(pipeFd int) {
pipeFd, err := strconv.Atoi(os.Args[2])
if err != nil {
panic(err)
}
fmt.Printf("child: pipeFd %d\n", pipeFd)
f, err := os.CreateTemp("", "tmpfile-")
if err != nil {
panic(err)
}
//defer os.Remove(f.Name())
//defer f.Close()
fd := int(f.Fd())
fmt.Printf("child: opened tmp file with fd %d\n", fd)
rights := unix.UnixRights(fd)
if err := unix.Sendmsg(pipeFd, nil, rights, nil, 0); err != nil {
panic(err)
}
fmt.Println("child: Sendmsg success")
_, err = unix.Write(pipeFd, []byte(dataPayload))
if err != nil {
panic(err)
}
fmt.Println("child: Write success")
} example with nil payload in unix.Sendmsg and without unix.Writeoutputwith
with it hangs with the following output
So it confirms the assumption that codepackage main
import (
"fmt"
"os"
"os/exec"
"strconv"
"golang.org/x/sys/unix"
)
const dataPayload = "hello"
func main() {
if len(os.Args) > 2 && os.Args[1] == "child" {
pipeFd, err := strconv.Atoi(os.Args[2])
if err != nil {
panic(err)
}
child(pipeFd)
} else {
parent()
}
}
func parent() {
fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
if err != nil {
panic(err)
}
defer unix.Close(fds[0])
defer unix.Close(fds[1])
parentPipeFd := fds[0]
// set clo_exec flag on parent file descriptor
_, err = unix.FcntlInt(uintptr(parentPipeFd), unix.F_SETFD, unix.FD_CLOEXEC)
if err != nil {
panic(err)
}
cmd := exec.Command("/proc/self/exe", "child", strconv.Itoa(fds[1]))
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = cmd.Start(); err != nil {
panic(err)
}
// receive socket control message
b := make([]byte, unix.CmsgSpace(4))
_, _, _, _, err = unix.Recvmsg(parentPipeFd, nil, b, 0)
if err != nil {
panic(err)
}
fmt.Println("parent: recvmsg success")
//data := make([]byte, len(dataPayload))
//_, err = unix.Read(parentPipeFd, data)
//if err != nil {
// panic(err)
//}
//fmt.Printf("parent: read success [%s]\n", data)
// parse socket control message
cmsgs, err := unix.ParseSocketControlMessage(b)
if err != nil {
panic(err)
}
fmt.Println("parent: parseSocketControlMessage success")
receivedFds, err := unix.ParseUnixRights(&cmsgs[0])
if err != nil {
panic(err)
}
fmt.Println("parent: ParseUnixRights success")
receivedFd := receivedFds[0]
defer unix.Close(receivedFd)
fmt.Printf("parent: got fd %d\n", receivedFd)
if err = cmd.Wait(); err != nil {
panic(err)
}
}
func child(pipeFd int) {
pipeFd, err := strconv.Atoi(os.Args[2])
if err != nil {
panic(err)
}
fmt.Printf("child: pipeFd %d\n", pipeFd)
f, err := os.CreateTemp("", "tmpfile-")
if err != nil {
panic(err)
}
//defer os.Remove(f.Name())
//defer f.Close()
fd := int(f.Fd())
fmt.Printf("child: opened tmp file with fd %d\n", fd)
rights := unix.UnixRights(fd)
if err := unix.Sendmsg(pipeFd, nil, rights, nil, 0); err != nil {
panic(err)
}
fmt.Println("child: Sendmsg success")
//_, err = unix.Write(pipeFd, []byte(dataPayload))
//if err != nil {
// panic(err)
//}
//fmt.Println("child: Write success")
} |
The bug is here. When the code got refactored in 87e55d714810 for RecvmsgBuffers, this change was not made correctly. It is missing the line |
Change https://go.dev/cl/445255 mentions this issue: |
@v-byte-cpu thanks for the test case. @rittneje thanks for pointing out the error. I sent CL 445255 to fix this. |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I tried to pass file descriptor over unix domain socket
for sending process:
for receiving process:
What did you expect to see?
unix.ParseSocketControlMessage
successfully parses the messageWhat did you see instead?
unix.ParseSocketControlMessage
fails withinvalid argument
errorI performed a research and found out that the problem occurred after this commit golang/sys@87e55d7
The text was updated successfully, but these errors were encountered: