summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux
diff options
context:
space:
mode:
authorTing-Yu Wang <anivia@google.com>2021-01-15 15:03:30 -0800
committergVisor bot <gvisor-bot@google.com>2021-01-15 15:10:27 -0800
commitec9e263f213c59e93f9c8b8123012b3db2dddc9a (patch)
tree87f0fca5791ece2a138fe822b4067569425f6bd2 /test/syscalls/linux
parent55c7fe48d223ee5678dff7f5bf9a9e5f0482ab37 (diff)
Correctly return EMSGSIZE when packet is too big in raw socket.
IPv4 previously accepts the packet, while IPv6 panics. Neither is the behavior in Linux. splice() in Linux has different behavior than in gVisor. This change documents it in the SpliceTooLong test. Reported-by: syzbot+b550e78e5c24d1d521f2@syzkaller.appspotmail.com PiperOrigin-RevId: 352091286
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r--test/syscalls/linux/packet_socket_raw.cc52
-rw-r--r--test/syscalls/linux/socket_test_util.cc13
-rw-r--r--test/syscalls/linux/socket_test_util.h7
3 files changed, 71 insertions, 1 deletions
diff --git a/test/syscalls/linux/packet_socket_raw.cc b/test/syscalls/linux/packet_socket_raw.cc
index a7c46adbf..2ed4f6f9c 100644
--- a/test/syscalls/linux/packet_socket_raw.cc
+++ b/test/syscalls/linux/packet_socket_raw.cc
@@ -678,6 +678,58 @@ TEST_P(RawPacketTest, GetSocketAcceptConn) {
INSTANTIATE_TEST_SUITE_P(AllInetTests, RawPacketTest,
::testing::Values(ETH_P_IP, ETH_P_ALL));
+class RawPacketMsgSizeTest : public ::testing::TestWithParam<TestAddress> {};
+
+TEST_P(RawPacketMsgSizeTest, SendTooLong) {
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+
+ TestAddress addr = GetParam().WithPort(kPort);
+
+ FileDescriptor udp_sock =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(addr.family(), SOCK_RAW, IPPROTO_UDP));
+
+ ASSERT_THAT(
+ connect(udp_sock.get(), reinterpret_cast<struct sockaddr*>(&addr.addr),
+ addr.addr_len),
+ SyscallSucceeds());
+
+ const char buf[65536] = {};
+ ASSERT_THAT(send(udp_sock.get(), buf, sizeof(buf), 0),
+ SyscallFailsWithErrno(EMSGSIZE));
+}
+
+TEST_P(RawPacketMsgSizeTest, SpliceTooLong) {
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+
+ const char buf[65536] = {};
+ int fds[2];
+ ASSERT_THAT(pipe(fds), SyscallSucceeds());
+ ASSERT_THAT(write(fds[1], buf, sizeof(buf)),
+ SyscallSucceedsWithValue(sizeof(buf)));
+
+ TestAddress addr = GetParam().WithPort(kPort);
+
+ FileDescriptor udp_sock =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(addr.family(), SOCK_RAW, IPPROTO_UDP));
+
+ ASSERT_THAT(
+ connect(udp_sock.get(), reinterpret_cast<struct sockaddr*>(&addr.addr),
+ addr.addr_len),
+ SyscallSucceeds());
+
+ ssize_t n = splice(fds[0], nullptr, udp_sock.get(), nullptr, sizeof(buf), 0);
+ if (IsRunningOnGvisor()) {
+ EXPECT_THAT(n, SyscallFailsWithErrno(EMSGSIZE));
+ } else {
+ // TODO(gvisor.dev/issue/138): Linux sends out multiple UDP datagrams, each
+ // of the size of a page.
+ EXPECT_THAT(n, SyscallSucceedsWithValue(sizeof(buf)));
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(AllRawPacketMsgSizeTest, RawPacketMsgSizeTest,
+ ::testing::Values(V4Loopback(), V6Loopback()));
+
} // namespace
} // namespace testing
diff --git a/test/syscalls/linux/socket_test_util.cc b/test/syscalls/linux/socket_test_util.cc
index 26dacc95e..b2a96086c 100644
--- a/test/syscalls/linux/socket_test_util.cc
+++ b/test/syscalls/linux/socket_test_util.cc
@@ -791,6 +791,19 @@ void RecvNoData(int sock) {
SyscallFailsWithErrno(EAGAIN));
}
+TestAddress TestAddress::WithPort(uint16_t port) const {
+ TestAddress addr = *this;
+ switch (addr.family()) {
+ case AF_INET:
+ reinterpret_cast<sockaddr_in*>(&addr.addr)->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ reinterpret_cast<sockaddr_in6*>(&addr.addr)->sin6_port = htons(port);
+ break;
+ }
+ return addr;
+}
+
TestAddress V4Any() {
TestAddress t("V4Any");
t.addr.ss_family = AF_INET;
diff --git a/test/syscalls/linux/socket_test_util.h b/test/syscalls/linux/socket_test_util.h
index 75c0d4735..b3ab286b8 100644
--- a/test/syscalls/linux/socket_test_util.h
+++ b/test/syscalls/linux/socket_test_util.h
@@ -486,9 +486,14 @@ struct TestAddress {
sockaddr_storage addr;
socklen_t addr_len;
- int family() const { return addr.ss_family; }
explicit TestAddress(std::string description = "")
: description(std::move(description)), addr(), addr_len() {}
+
+ int family() const { return addr.ss_family; }
+
+ // Returns a new TestAddress with specified port. If port is not supported,
+ // the same TestAddress is returned.
+ TestAddress WithPort(uint16_t port) const;
};
constexpr char kMulticastAddress[] = "224.0.2.1";