diff options
author | Dean Deng <deandeng@google.com> | 2021-01-26 09:47:24 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-01-26 09:49:31 -0800 |
commit | abdff887483f1d9487bffa0278dd6f7a40e59a74 (patch) | |
tree | 94c35cfbf9487a5c9888fad352b971e09715b61e /test | |
parent | daf0d3f6ca3aad6f3f9ab4d762546c6dee78fa57 (diff) |
Do not send SCM Rights more than once when message is truncated.
If data is sent over a stream socket that will not fit all at once, it will
be sent over multiple packets. SCM Rights should only be sent with the first
packet (see net/unix/af_unix.c:unix_stream_sendmsg in Linux).
Reported-by: syzbot+aa26482e9c4887aff259@syzkaller.appspotmail.com
PiperOrigin-RevId: 353886442
Diffstat (limited to 'test')
-rw-r--r-- | test/syscalls/linux/socket.cc | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/test/syscalls/linux/socket.cc b/test/syscalls/linux/socket.cc index 32f583581..1af72b159 100644 --- a/test/syscalls/linux/socket.cc +++ b/test/syscalls/linux/socket.cc @@ -16,6 +16,7 @@ #include <sys/stat.h> #include <sys/statfs.h> #include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> #include "gtest/gtest.h" @@ -111,6 +112,77 @@ TEST(SocketTest, UnixSocketStatFS) { EXPECT_EQ(st.f_namelen, NAME_MAX); } +TEST(SocketTest, UnixSCMRightsOnlyPassedOnce_NoRandomSave) { + const DisableSave ds; + + int sockets[2]; + ASSERT_THAT(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets), SyscallSucceeds()); + // Send more than what will fit inside the send/receive buffers, so that it is + // split into multiple messages. + constexpr int kBufSize = 0x100000; + + pid_t pid = fork(); + if (pid == 0) { + TEST_PCHECK(close(sockets[0]) == 0); + + // Construct a message with some control message. + struct msghdr msg = {}; + char control[CMSG_SPACE(sizeof(int))] = {}; + std::vector<char> buf(kBufSize); + struct iovec iov = {}; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + ((int*)CMSG_DATA(cmsg))[0] = sockets[1]; + + iov.iov_base = buf.data(); + iov.iov_len = kBufSize; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + int n = sendmsg(sockets[1], &msg, 0); + TEST_PCHECK(n == kBufSize); + TEST_PCHECK(shutdown(sockets[1], SHUT_RDWR) == 0); + TEST_PCHECK(close(sockets[1]) == 0); + _exit(0); + } + + close(sockets[1]); + + struct msghdr msg = {}; + char control[CMSG_SPACE(sizeof(int))] = {}; + std::vector<char> buf(kBufSize); + struct iovec iov = {}; + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + iov.iov_base = buf.data(); + iov.iov_len = kBufSize; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + // The control message should only be present in the first message received. + int n; + ASSERT_THAT(n = recvmsg(sockets[0], &msg, 0), SyscallSucceeds()); + ASSERT_GT(n, 0); + ASSERT_EQ(msg.msg_controllen, CMSG_SPACE(sizeof(int))); + + while (n > 0) { + ASSERT_THAT(n = recvmsg(sockets[0], &msg, 0), SyscallSucceeds()); + ASSERT_EQ(msg.msg_controllen, 0); + } + + close(sockets[0]); + + int status; + ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid)); + ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); +} + using SocketOpenTest = ::testing::TestWithParam<int>; // UDS cannot be opened. |