gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/socket_inet_loopback_nogotsan.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <arpa/inet.h> 16 #include <netinet/in.h> 17 #include <netinet/tcp.h> 18 #include <string.h> 19 20 #include <iostream> 21 #include <memory> 22 #include <string> 23 #include <utility> 24 #include <vector> 25 26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 28 #include "absl/strings/str_cat.h" 29 #include "test/syscalls/linux/ip_socket_test_util.h" 30 #include "test/syscalls/linux/socket_inet_loopback_test_params.h" 31 #include "test/util/file_descriptor.h" 32 #include "test/util/posix_error.h" 33 #include "test/util/save_util.h" 34 #include "test/util/socket_util.h" 35 #include "test/util/test_util.h" 36 37 namespace gvisor { 38 namespace testing { 39 40 namespace { 41 42 using SocketInetLoopbackTest = ::testing::TestWithParam<SocketInetTestParam>; 43 44 // This test verifies that connect returns EADDRNOTAVAIL if all local ephemeral 45 // ports are already in use for a given destination ip/port. 46 // 47 // We disable S/R because this test creates a large number of sockets. 48 // 49 // FIXME(b/162475855): This test is failing reliably. 50 TEST_P(SocketInetLoopbackTest, DISABLED_TestTCPPortExhaustion) { 51 SocketInetTestParam const& param = GetParam(); 52 TestAddress const& listener = param.listener; 53 TestAddress const& connector = param.connector; 54 55 constexpr int kBacklog = 10; 56 constexpr int kClients = 65536; 57 58 // Create the listening socket. 59 auto listen_fd = ASSERT_NO_ERRNO_AND_VALUE( 60 Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP)); 61 sockaddr_storage listen_addr = listener.addr; 62 ASSERT_THAT( 63 bind(listen_fd.get(), AsSockAddr(&listen_addr), listener.addr_len), 64 SyscallSucceeds()); 65 ASSERT_THAT(listen(listen_fd.get(), kBacklog), SyscallSucceeds()); 66 67 // Get the port bound by the listening socket. 68 socklen_t addrlen = listener.addr_len; 69 ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(&listen_addr), &addrlen), 70 SyscallSucceeds()); 71 uint16_t const port = 72 ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr)); 73 74 // Disable cooperative S/R as we are making too many syscalls. 75 DisableSave ds; 76 77 // Now we keep opening connections till we run out of local ephemeral ports. 78 // and assert the error we get back. 79 sockaddr_storage conn_addr = connector.addr; 80 ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port)); 81 std::vector<FileDescriptor> clients; 82 std::vector<FileDescriptor> servers; 83 84 for (int i = 0; i < kClients; i++) { 85 FileDescriptor client = ASSERT_NO_ERRNO_AND_VALUE( 86 Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP)); 87 int ret = connect(client.get(), AsSockAddr(&conn_addr), connector.addr_len); 88 if (ret == 0) { 89 clients.push_back(std::move(client)); 90 FileDescriptor server = 91 ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_fd.get(), nullptr, nullptr)); 92 servers.push_back(std::move(server)); 93 continue; 94 } 95 ASSERT_THAT(ret, SyscallFailsWithErrno(EADDRNOTAVAIL)); 96 break; 97 } 98 } 99 100 INSTANTIATE_TEST_SUITE_P(All, SocketInetLoopbackTest, 101 SocketInetLoopbackTestValues(), 102 DescribeSocketInetTestParam); 103 104 using SocketMultiProtocolInetLoopbackTest = 105 ::testing::TestWithParam<ProtocolTestParam>; 106 107 TEST_P(SocketMultiProtocolInetLoopbackTest, 108 TCPBindAvoidsOtherBoundPortsReuseAddr) { 109 ProtocolTestParam const& param = GetParam(); 110 // UDP sockets are allowed to bind/listen on an already bound port w/ 111 // SO_REUSEADDR even when requesting a port from the kernel. In case of TCP 112 // rebinding is only permitted when SO_REUSEADDR is set and an explicit port 113 // is specified. When a zero port is specified to the bind() call then an 114 // already bound port will not be picked. 115 SKIP_IF(param.type != SOCK_STREAM); 116 117 DisableSave ds; // Too many syscalls. 118 119 // A map of port to file descriptor binding the port. 120 std::map<uint16_t, FileDescriptor> bound_sockets; 121 122 // Reduce number of ephemeral ports if permitted to reduce running time of 123 // the test. 124 [[maybe_unused]] const int nports = 125 ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 126 127 // Exhaust all ephemeral ports. 128 while (true) { 129 // Bind the v4 loopback on a v4 socket. 130 TestAddress const& test_addr = V4Loopback(); 131 sockaddr_storage bound_addr = test_addr.addr; 132 FileDescriptor bound_fd = 133 ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0)); 134 135 ASSERT_THAT(setsockopt(bound_fd.get(), SOL_SOCKET, SO_REUSEADDR, 136 &kSockOptOn, sizeof(kSockOptOn)), 137 SyscallSucceeds()); 138 139 int ret = bind(bound_fd.get(), AsSockAddr(&bound_addr), test_addr.addr_len); 140 if (ret != 0) { 141 ASSERT_EQ(errno, EADDRINUSE); 142 break; 143 } 144 // Get the port that we bound. 145 socklen_t bound_addr_len = test_addr.addr_len; 146 ASSERT_THAT( 147 getsockname(bound_fd.get(), AsSockAddr(&bound_addr), &bound_addr_len), 148 SyscallSucceeds()); 149 uint16_t port = reinterpret_cast<sockaddr_in*>(&bound_addr)->sin_port; 150 151 auto [iter, inserted] = bound_sockets.emplace(port, std::move(bound_fd)); 152 ASSERT_TRUE(inserted); 153 } 154 } 155 156 TEST_P(SocketMultiProtocolInetLoopbackTest, 157 UDPBindMayBindOtherBoundPortsReuseAddr) { 158 ProtocolTestParam const& param = GetParam(); 159 // UDP sockets are allowed to bind/listen on an already bound port w/ 160 // SO_REUSEADDR even when requesting a port from the kernel. 161 SKIP_IF(param.type != SOCK_DGRAM); 162 163 DisableSave ds; // Too many syscalls. 164 165 // A map of port to file descriptor binding the port. 166 std::map<uint16_t, FileDescriptor> bound_sockets; 167 168 // Reduce number of ephemeral ports if permitted to reduce running time of 169 // the test. 170 [[maybe_unused]] const int nports = 171 ASSERT_NO_ERRNO_AND_VALUE(MaybeLimitEphemeralPorts()); 172 173 // Exhaust all ephemeral ports. 174 bool duplicate_binding = false; 175 while (true) { 176 // Bind the v4 loopback on a v4 socket. 177 TestAddress const& test_addr = V4Loopback(); 178 sockaddr_storage bound_addr = test_addr.addr; 179 FileDescriptor bound_fd = 180 ASSERT_NO_ERRNO_AND_VALUE(Socket(test_addr.family(), param.type, 0)); 181 182 ASSERT_THAT(setsockopt(bound_fd.get(), SOL_SOCKET, SO_REUSEADDR, 183 &kSockOptOn, sizeof(kSockOptOn)), 184 SyscallSucceeds()); 185 186 ASSERT_THAT( 187 bind(bound_fd.get(), AsSockAddr(&bound_addr), test_addr.addr_len), 188 SyscallSucceeds()); 189 190 // Get the port that we bound. 191 socklen_t bound_addr_len = test_addr.addr_len; 192 ASSERT_THAT( 193 getsockname(bound_fd.get(), AsSockAddr(&bound_addr), &bound_addr_len), 194 SyscallSucceeds()); 195 uint16_t port = reinterpret_cast<sockaddr_in*>(&bound_addr)->sin_port; 196 197 auto [iter, inserted] = bound_sockets.emplace(port, std::move(bound_fd)); 198 if (!inserted) { 199 duplicate_binding = true; 200 break; 201 } 202 } 203 ASSERT_TRUE(duplicate_binding); 204 } 205 206 INSTANTIATE_TEST_SUITE_P(AllFamilies, SocketMultiProtocolInetLoopbackTest, 207 ProtocolTestValues(), DescribeProtocolTestParam); 208 209 } // namespace 210 211 } // namespace testing 212 } // namespace gvisor