diff options
author | Ian Gudger <igudger@google.com> | 2019-04-19 16:15:37 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-04-19 16:17:01 -0700 |
commit | 358eb52a76ebd41baf52972f901af0ff398e131b (patch) | |
tree | 90812de0d36a1fde5b8a5ddb8e39a44d206be8e7 /test/syscalls/linux | |
parent | cec2cdc12f30e87e5b0f6750fe1c132d89fcfb6d (diff) |
Add support for the MSG_TRUNC msghdr flag.
The MSG_TRUNC flag is set in the msghdr when a message is truncated.
Fixes google/gvisor#200
PiperOrigin-RevId: 244440486
Change-Id: I03c7d5e7f5935c0c6b8d69b012db1780ac5b8456
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r-- | test/syscalls/linux/socket_netlink_route.cc | 80 | ||||
-rw-r--r-- | test/syscalls/linux/socket_non_stream.cc | 55 | ||||
-rw-r--r-- | test/syscalls/linux/socket_stream.cc | 27 |
3 files changed, 162 insertions, 0 deletions
diff --git a/test/syscalls/linux/socket_netlink_route.cc b/test/syscalls/linux/socket_netlink_route.cc index 5f83836df..fa895d841 100644 --- a/test/syscalls/linux/socket_netlink_route.cc +++ b/test/syscalls/linux/socket_netlink_route.cc @@ -220,6 +220,86 @@ TEST(NetlinkRouteTest, GetLinkDump) { EXPECT_TRUE(loopbackFound); } +TEST(NetlinkRouteTest, MsgHdrMsgTrunc) { + FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket()); + + struct request { + struct nlmsghdr hdr; + struct ifinfomsg ifm; + }; + + constexpr uint32_t kSeq = 12345; + + struct request req = {}; + req.hdr.nlmsg_len = sizeof(req); + req.hdr.nlmsg_type = RTM_GETLINK; + req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.hdr.nlmsg_seq = kSeq; + req.ifm.ifi_family = AF_UNSPEC; + + struct iovec iov = {}; + iov.iov_base = &req; + iov.iov_len = sizeof(req); + + struct msghdr msg = {}; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + // No destination required; it defaults to pid 0, the kernel. + + ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); + + // Small enough to ensure that the response doesn't fit. + constexpr size_t kBufferSize = 10; + std::vector<char> buf(kBufferSize); + iov.iov_base = buf.data(); + iov.iov_len = buf.size(); + + ASSERT_THAT(RetryEINTR(recvmsg)(fd.get(), &msg, 0), + SyscallSucceedsWithValue(kBufferSize)); + EXPECT_EQ((msg.msg_flags & MSG_TRUNC), MSG_TRUNC); +} + +TEST(NetlinkRouteTest, MsgTruncMsgHdrMsgTrunc) { + FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket()); + + struct request { + struct nlmsghdr hdr; + struct ifinfomsg ifm; + }; + + constexpr uint32_t kSeq = 12345; + + struct request req = {}; + req.hdr.nlmsg_len = sizeof(req); + req.hdr.nlmsg_type = RTM_GETLINK; + req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.hdr.nlmsg_seq = kSeq; + req.ifm.ifi_family = AF_UNSPEC; + + struct iovec iov = {}; + iov.iov_base = &req; + iov.iov_len = sizeof(req); + + struct msghdr msg = {}; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + // No destination required; it defaults to pid 0, the kernel. + + ASSERT_THAT(RetryEINTR(sendmsg)(fd.get(), &msg, 0), SyscallSucceeds()); + + // Small enough to ensure that the response doesn't fit. + constexpr size_t kBufferSize = 10; + std::vector<char> buf(kBufferSize); + iov.iov_base = buf.data(); + iov.iov_len = buf.size(); + + int res = 0; + ASSERT_THAT(res = RetryEINTR(recvmsg)(fd.get(), &msg, MSG_TRUNC), + SyscallSucceeds()); + EXPECT_GT(res, kBufferSize); + EXPECT_EQ((msg.msg_flags & MSG_TRUNC), MSG_TRUNC); +} + TEST(NetlinkRouteTest, ControlMessageIgnored) { FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket()); uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); diff --git a/test/syscalls/linux/socket_non_stream.cc b/test/syscalls/linux/socket_non_stream.cc index d49aab363..d170008a4 100644 --- a/test/syscalls/linux/socket_non_stream.cc +++ b/test/syscalls/linux/socket_non_stream.cc @@ -15,6 +15,7 @@ #include "test/syscalls/linux/socket_non_stream.h" #include <stdio.h> +#include <sys/socket.h> #include <sys/un.h> #include "gtest/gtest.h" @@ -89,6 +90,33 @@ TEST_P(NonStreamSocketPairTest, SingleRecv) { EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); } +TEST_P(NonStreamSocketPairTest, RecvmsgMsghdrFlagMsgTrunc) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + char sent_data[10]; + RandomizeBuffer(sent_data, sizeof(sent_data)); + ASSERT_THAT( + RetryEINTR(send)(sockets->first_fd(), sent_data, sizeof(sent_data), 0), + SyscallSucceedsWithValue(sizeof(sent_data))); + + char received_data[sizeof(sent_data) / 2] = {}; + + struct iovec iov; + iov.iov_base = received_data; + iov.iov_len = sizeof(received_data); + struct msghdr msg = {}; + msg.msg_flags = -1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ASSERT_THAT(RetryEINTR(recvmsg)(sockets->second_fd(), &msg, 0), + SyscallSucceedsWithValue(sizeof(received_data))); + EXPECT_EQ(0, memcmp(received_data, sent_data, sizeof(received_data))); + + // Check that msghdr flags were updated. + EXPECT_EQ(msg.msg_flags, MSG_TRUNC); +} + // Stream sockets allow data sent with multiple sends to be peeked at in a // single recv. Datagram sockets (except for unix sockets) do not. // @@ -142,6 +170,33 @@ TEST_P(NonStreamSocketPairTest, MsgTruncTruncation) { sizeof(sent_data) / 2)); } +TEST_P(NonStreamSocketPairTest, MsgTruncTruncationRecvmsgMsghdrFlagMsgTrunc) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + char sent_data[10]; + RandomizeBuffer(sent_data, sizeof(sent_data)); + ASSERT_THAT( + RetryEINTR(send)(sockets->first_fd(), sent_data, sizeof(sent_data), 0), + SyscallSucceedsWithValue(sizeof(sent_data))); + + char received_data[sizeof(sent_data) / 2] = {}; + + struct iovec iov; + iov.iov_base = received_data; + iov.iov_len = sizeof(received_data); + struct msghdr msg = {}; + msg.msg_flags = -1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ASSERT_THAT(RetryEINTR(recvmsg)(sockets->second_fd(), &msg, MSG_TRUNC), + SyscallSucceedsWithValue(sizeof(sent_data))); + EXPECT_EQ(0, memcmp(received_data, sent_data, sizeof(received_data))); + + // Check that msghdr flags were updated. + EXPECT_EQ(msg.msg_flags, MSG_TRUNC); +} + TEST_P(NonStreamSocketPairTest, MsgTruncSameSize) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[512]; diff --git a/test/syscalls/linux/socket_stream.cc b/test/syscalls/linux/socket_stream.cc index 32e9d958b..c8a8ad0f6 100644 --- a/test/syscalls/linux/socket_stream.cc +++ b/test/syscalls/linux/socket_stream.cc @@ -81,6 +81,33 @@ TEST_P(StreamSocketPairTest, WriteOneSideClosed) { SyscallFailsWithErrno(EPIPE)); } +TEST_P(StreamSocketPairTest, RecvmsgMsghdrFlagsNoMsgTrunc) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + char sent_data[10]; + RandomizeBuffer(sent_data, sizeof(sent_data)); + ASSERT_THAT( + RetryEINTR(send)(sockets->first_fd(), sent_data, sizeof(sent_data), 0), + SyscallSucceedsWithValue(sizeof(sent_data))); + + char received_data[sizeof(sent_data) / 2] = {}; + + struct iovec iov; + iov.iov_base = received_data; + iov.iov_len = sizeof(received_data); + struct msghdr msg = {}; + msg.msg_flags = -1; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ASSERT_THAT(RetryEINTR(recvmsg)(sockets->second_fd(), &msg, 0), + SyscallSucceedsWithValue(sizeof(received_data))); + EXPECT_EQ(0, memcmp(received_data, sent_data, sizeof(received_data))); + + // Check that msghdr flags were cleared (MSG_TRUNC was not set). + EXPECT_EQ(msg.msg_flags, 0); +} + TEST_P(StreamSocketPairTest, MsgTrunc) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[512]; |