summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
authorMithun Iyer <iyerm@google.com>2021-04-17 11:30:36 -0700
committergVisor bot <gvisor-bot@google.com>2021-04-17 11:32:17 -0700
commit9b4cc3d43bc79698762e1efa980148f12e8ad196 (patch)
tree15301debc1db874647b07f7b97a3d3a8256a96ee /test/syscalls
parent3b685753b4e9632ed8cde1ae284c79a9a14230b9 (diff)
Avoid ignoring incoming packet by demuxer on endpoint lookup failure
This fixes a race that occurs while the endpoint is being unregistered and the transport demuxer attempts to match the incoming packet to any endpoint. The race specifically occurs when the unregistration (and deletion of the endpoint) occurs, after a successful endpointsByNIC lookup and before the endpoints map is further looked up with ingress NICID of the packet. The fix is to notify the caller of lookup-with-NICID failure, so that the logic falls through to handling unknown destination packets. For TCP this can mean replying back with RST. The syscall test in this CL catches this race as the ACK completing the handshake could get silently dropped on a listener close, causing no RST sent to the peer and timing out the poll waiting for POLLHUP. Fixes #5850 PiperOrigin-RevId: 369023779
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/socket_inet_loopback.cc75
1 files changed, 39 insertions, 36 deletions
diff --git a/test/syscalls/linux/socket_inet_loopback.cc b/test/syscalls/linux/socket_inet_loopback.cc
index 38e6f8b5c..9a6b089f6 100644
--- a/test/syscalls/linux/socket_inet_loopback.cc
+++ b/test/syscalls/linux/socket_inet_loopback.cc
@@ -477,47 +477,50 @@ void TestHangupDuringConnect(const TestParam& param,
TestAddress const& listener = param.listener;
TestAddress const& connector = param.connector;
- // Create the listening socket.
- FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
- Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP));
- sockaddr_storage listen_addr = listener.addr;
- ASSERT_THAT(bind(listen_fd.get(), reinterpret_cast<sockaddr*>(&listen_addr),
- listener.addr_len),
- SyscallSucceeds());
- ASSERT_THAT(listen(listen_fd.get(), 1), SyscallSucceeds());
+ for (int i = 0; i < 100; i++) {
+ // Create the listening socket.
+ FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP));
+ sockaddr_storage listen_addr = listener.addr;
+ ASSERT_THAT(bind(listen_fd.get(), reinterpret_cast<sockaddr*>(&listen_addr),
+ listener.addr_len),
+ SyscallSucceeds());
+ ASSERT_THAT(listen(listen_fd.get(), 0), SyscallSucceeds());
- // Get the port bound by the listening socket.
- socklen_t addrlen = listener.addr_len;
- ASSERT_THAT(getsockname(listen_fd.get(),
- reinterpret_cast<sockaddr*>(&listen_addr), &addrlen),
- SyscallSucceeds());
- uint16_t const port =
- ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
+ // Get the port bound by the listening socket.
+ socklen_t addrlen = listener.addr_len;
+ ASSERT_THAT(
+ getsockname(listen_fd.get(), reinterpret_cast<sockaddr*>(&listen_addr),
+ &addrlen),
+ SyscallSucceeds());
+ uint16_t const port =
+ ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
- sockaddr_storage conn_addr = connector.addr;
- ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
+ sockaddr_storage conn_addr = connector.addr;
+ ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
- // Connect asynchronously and immediately hang up the listener.
- FileDescriptor client = ASSERT_NO_ERRNO_AND_VALUE(
- Socket(connector.family(), SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP));
- int ret = connect(client.get(), reinterpret_cast<sockaddr*>(&conn_addr),
- connector.addr_len);
- if (ret != 0) {
- EXPECT_THAT(ret, SyscallFailsWithErrno(EINPROGRESS));
- }
+ // Connect asynchronously and immediately hang up the listener.
+ FileDescriptor client = ASSERT_NO_ERRNO_AND_VALUE(
+ Socket(connector.family(), SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP));
+ int ret = connect(client.get(), reinterpret_cast<sockaddr*>(&conn_addr),
+ connector.addr_len);
+ if (ret != 0) {
+ EXPECT_THAT(ret, SyscallFailsWithErrno(EINPROGRESS));
+ }
- hangup(listen_fd);
+ hangup(listen_fd);
- // Wait for the connection to close.
- struct pollfd pfd = {
- .fd = client.get(),
- };
- constexpr int kTimeout = 10000;
- int n = poll(&pfd, 1, kTimeout);
- ASSERT_GE(n, 0) << strerror(errno);
- ASSERT_EQ(n, 1);
- ASSERT_EQ(pfd.revents, POLLHUP | POLLERR);
- ASSERT_EQ(close(client.release()), 0) << strerror(errno);
+ // Wait for the connection to close.
+ struct pollfd pfd = {
+ .fd = client.get(),
+ };
+ constexpr int kTimeout = 10000;
+ int n = poll(&pfd, 1, kTimeout);
+ ASSERT_GE(n, 0) << strerror(errno);
+ ASSERT_EQ(n, 1);
+ ASSERT_EQ(pfd.revents, POLLHUP | POLLERR);
+ ASSERT_EQ(close(client.release()), 0) << strerror(errno);
+ }
}
TEST_P(SocketInetLoopbackTest, TCPListenCloseDuringConnect) {