github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/socket_unix_non_stream.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 "test/syscalls/linux/socket_unix_non_stream.h" 16 17 #include <stdio.h> 18 #include <sys/mman.h> 19 #include <sys/un.h> 20 21 #include "gtest/gtest.h" 22 #include "test/syscalls/linux/socket_test_util.h" 23 #include "test/syscalls/linux/unix_domain_socket_test_util.h" 24 #include "test/util/memory_util.h" 25 #include "test/util/test_util.h" 26 27 namespace gvisor { 28 namespace testing { 29 30 TEST_P(UnixNonStreamSocketPairTest, RecvMsgTooLarge) { 31 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 32 33 int rcvbuf; 34 socklen_t length = sizeof(rcvbuf); 35 ASSERT_THAT( 36 getsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUF, &rcvbuf, &length), 37 SyscallSucceeds()); 38 39 // Make the call larger than the receive buffer. 40 const int recv_size = 3 * rcvbuf; 41 42 // Write a message that does fit in the receive buffer. 43 const int write_size = rcvbuf - kPageSize; 44 45 std::vector<char> write_buf(write_size, 'a'); 46 const int ret = RetryEINTR(write)(sockets->second_fd(), write_buf.data(), 47 write_buf.size()); 48 if (ret < 0 && errno == ENOBUFS) { 49 // NOTE(b/116636318): Linux may stall the write for a long time and 50 // ultimately return ENOBUFS. Allow this error, since a retry will likely 51 // result in the same error. 52 return; 53 } 54 ASSERT_THAT(ret, SyscallSucceeds()); 55 56 std::vector<char> recv_buf(recv_size); 57 58 ASSERT_NO_FATAL_FAILURE(RecvNoCmsg(sockets->first_fd(), recv_buf.data(), 59 recv_buf.size(), write_size)); 60 61 recv_buf.resize(write_size); 62 EXPECT_EQ(recv_buf, write_buf); 63 } 64 65 // Create a region of anonymous memory of size 'size', which is fragmented in 66 // FileMem. 67 // 68 // ptr contains the start address of the region. The returned vector contains 69 // all of the mappings to be unmapped when done. 70 PosixErrorOr<std::vector<Mapping>> CreateFragmentedRegion(const int size, 71 void** ptr) { 72 Mapping region; 73 ASSIGN_OR_RETURN_ERRNO(region, Mmap(nullptr, size, PROT_NONE, 74 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); 75 76 *ptr = region.ptr(); 77 78 // Don't save hundreds of times for all of these mmaps. 79 DisableSave ds; 80 81 std::vector<Mapping> pages; 82 83 // Map and commit a single page at a time, mapping and committing an unrelated 84 // page between each call to force FileMem fragmentation. 85 for (uintptr_t addr = region.addr(); addr < region.endaddr(); 86 addr += kPageSize) { 87 Mapping page; 88 ASSIGN_OR_RETURN_ERRNO( 89 page, 90 Mmap(reinterpret_cast<void*>(addr), kPageSize, PROT_READ | PROT_WRITE, 91 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)); 92 *reinterpret_cast<volatile char*>(page.ptr()) = 42; 93 94 pages.emplace_back(std::move(page)); 95 96 // Unrelated page elsewhere. 97 ASSIGN_OR_RETURN_ERRNO(page, 98 Mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE, 99 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); 100 *reinterpret_cast<volatile char*>(page.ptr()) = 42; 101 102 pages.emplace_back(std::move(page)); 103 } 104 105 // The mappings above have taken ownership of the region. 106 region.release(); 107 108 return std::move(pages); 109 } 110 111 // A contiguous iov that is heavily fragmented in FileMem can still be sent 112 // successfully. See b/115833655. 113 TEST_P(UnixNonStreamSocketPairTest, FragmentedSendMsg) { 114 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 115 116 const int buffer_size = UIO_MAXIOV * kPageSize; 117 // Extra page for message header overhead. 118 const int sndbuf = buffer_size + kPageSize; 119 // N.B. setsockopt(SO_SNDBUF) doubles the passed value. 120 const int set_sndbuf = sndbuf / 2; 121 122 EXPECT_THAT(setsockopt(sockets->first_fd(), SOL_SOCKET, SO_SNDBUF, 123 &set_sndbuf, sizeof(set_sndbuf)), 124 SyscallSucceeds()); 125 126 int actual_sndbuf = 0; 127 socklen_t length = sizeof(actual_sndbuf); 128 ASSERT_THAT(getsockopt(sockets->first_fd(), SOL_SOCKET, SO_SNDBUF, 129 &actual_sndbuf, &length), 130 SyscallSucceeds()); 131 132 if (actual_sndbuf != sndbuf) { 133 // Unable to get the sndbuf we want. 134 // 135 // N.B. At minimum, the socketpair gofer should provide a socket that is 136 // already the correct size. 137 // 138 // TODO(b/35921550): When internal UDS support SO_SNDBUF, we can assert that 139 // we always get the right SO_SNDBUF on gVisor. 140 GTEST_SKIP() << "SO_SNDBUF = " << actual_sndbuf << ", want " << sndbuf; 141 } 142 143 // Create a contiguous region of memory of 2*UIO_MAXIOV*PAGE_SIZE. We'll call 144 // sendmsg with a single iov, but the goal is to get the sentry to split this 145 // into > UIO_MAXIOV iovs when calling the kernel. 146 void* ptr; 147 std::vector<Mapping> pages = 148 ASSERT_NO_ERRNO_AND_VALUE(CreateFragmentedRegion(buffer_size, &ptr)); 149 150 struct iovec iov = {}; 151 iov.iov_base = ptr; 152 iov.iov_len = buffer_size; 153 154 struct msghdr msg = {}; 155 msg.msg_iov = &iov; 156 msg.msg_iovlen = 1; 157 158 // NOTE(b/116636318,b/115833655): Linux has poor behavior in the presence of 159 // physical memory fragmentation. As a result, this may stall for a long time 160 // and ultimately return ENOBUFS. Allow this error, since it means that we 161 // made it to the host kernel and started the sendmsg. 162 EXPECT_THAT(RetryEINTR(sendmsg)(sockets->first_fd(), &msg, 0), 163 AnyOf(SyscallSucceedsWithValue(buffer_size), 164 SyscallFailsWithErrno(ENOBUFS))); 165 } 166 167 // A contiguous iov that is heavily fragmented in FileMem can still be received 168 // into successfully. Regression test for b/115833655. 169 TEST_P(UnixNonStreamSocketPairTest, FragmentedRecvMsg) { 170 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 171 172 const int buffer_size = UIO_MAXIOV * kPageSize; 173 // Extra page for message header overhead. 174 const int sndbuf = buffer_size + kPageSize; 175 // N.B. setsockopt(SO_SNDBUF) doubles the passed value. 176 const int set_sndbuf = sndbuf / 2; 177 178 EXPECT_THAT(setsockopt(sockets->first_fd(), SOL_SOCKET, SO_SNDBUF, 179 &set_sndbuf, sizeof(set_sndbuf)), 180 SyscallSucceeds()); 181 182 int actual_sndbuf = 0; 183 socklen_t length = sizeof(actual_sndbuf); 184 ASSERT_THAT(getsockopt(sockets->first_fd(), SOL_SOCKET, SO_SNDBUF, 185 &actual_sndbuf, &length), 186 SyscallSucceeds()); 187 188 if (actual_sndbuf != sndbuf) { 189 // Unable to get the sndbuf we want. 190 // 191 // N.B. At minimum, the socketpair gofer should provide a socket that is 192 // already the correct size. 193 // 194 // TODO(b/35921550): When internal UDS support SO_SNDBUF, we can assert that 195 // we always get the right SO_SNDBUF on gVisor. 196 GTEST_SKIP() << "SO_SNDBUF = " << actual_sndbuf << ", want " << sndbuf; 197 } 198 199 std::vector<char> write_buf(buffer_size, 'a'); 200 const int ret = RetryEINTR(write)(sockets->first_fd(), write_buf.data(), 201 write_buf.size()); 202 if (ret < 0 && errno == ENOBUFS) { 203 // NOTE(b/116636318): Linux may stall the write for a long time and 204 // ultimately return ENOBUFS. Allow this error, since a retry will likely 205 // result in the same error. 206 return; 207 } 208 ASSERT_THAT(ret, SyscallSucceeds()); 209 210 // Create a contiguous region of memory of 2*UIO_MAXIOV*PAGE_SIZE. We'll call 211 // sendmsg with a single iov, but the goal is to get the sentry to split this 212 // into > UIO_MAXIOV iovs when calling the kernel. 213 void* ptr; 214 std::vector<Mapping> pages = 215 ASSERT_NO_ERRNO_AND_VALUE(CreateFragmentedRegion(buffer_size, &ptr)); 216 217 ASSERT_NO_FATAL_FAILURE(RecvNoCmsg( 218 sockets->second_fd(), reinterpret_cast<char*>(ptr), buffer_size)); 219 220 EXPECT_EQ(0, memcmp(write_buf.data(), ptr, buffer_size)); 221 } 222 223 TEST_P(UnixNonStreamSocketPairTest, SendTimeout) { 224 auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); 225 226 struct timeval tv { 227 .tv_sec = 0, .tv_usec = 10 228 }; 229 EXPECT_THAT( 230 setsockopt(sockets->first_fd(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), 231 SyscallSucceeds()); 232 233 const int buf_size = 5 * kPageSize; 234 EXPECT_THAT(setsockopt(sockets->first_fd(), SOL_SOCKET, SO_SNDBUF, &buf_size, 235 sizeof(buf_size)), 236 SyscallSucceeds()); 237 EXPECT_THAT(setsockopt(sockets->second_fd(), SOL_SOCKET, SO_RCVBUF, &buf_size, 238 sizeof(buf_size)), 239 SyscallSucceeds()); 240 241 // The buffer size should be big enough to avoid many iterations in the next 242 // loop. Otherwise, this will slow down save tests. 243 std::vector<char> buf(kPageSize); 244 for (;;) { 245 int ret; 246 ASSERT_THAT( 247 ret = RetryEINTR(send)(sockets->first_fd(), buf.data(), buf.size(), 0), 248 ::testing::AnyOf(SyscallSucceeds(), SyscallFailsWithErrno(EAGAIN))); 249 if (ret == -1) { 250 break; 251 } 252 } 253 } 254 255 } // namespace testing 256 } // namespace gvisor