github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/partial_bad_buffer.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 <errno.h> 16 #include <fcntl.h> 17 #include <netinet/in.h> 18 #include <netinet/tcp.h> 19 #include <sys/mman.h> 20 #include <sys/socket.h> 21 #include <sys/stat.h> 22 #include <sys/syscall.h> 23 #include <sys/types.h> 24 #include <sys/uio.h> 25 #include <unistd.h> 26 27 #include "gtest/gtest.h" 28 #include "absl/time/clock.h" 29 #include "test/syscalls/linux/socket_test_util.h" 30 #include "test/util/file_descriptor.h" 31 #include "test/util/fs_util.h" 32 #include "test/util/posix_error.h" 33 #include "test/util/temp_path.h" 34 #include "test/util/test_util.h" 35 36 using ::testing::Gt; 37 38 namespace gvisor { 39 namespace testing { 40 41 namespace { 42 43 constexpr char kMessage[] = "hello world"; 44 45 // PartialBadBufferTest checks the result of various IO syscalls when passed a 46 // buffer that does not have the space specified in the syscall (most of it is 47 // PROT_NONE). Linux is annoyingly inconsistent among different syscalls, so we 48 // test all of them. 49 class PartialBadBufferTest : public ::testing::Test { 50 protected: 51 void SetUp() override { 52 // Create and open a directory for getdents cases. 53 directory_ = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 54 ASSERT_THAT( 55 directory_fd_ = open(directory_.path().c_str(), O_RDONLY | O_DIRECTORY), 56 SyscallSucceeds()); 57 58 // Create and open a normal file, placing it in the directory 59 // so the getdents cases have some dirents. 60 name_ = JoinPath(directory_.path(), "a"); 61 ASSERT_THAT(fd_ = open(name_.c_str(), O_RDWR | O_CREAT, 0644), 62 SyscallSucceeds()); 63 64 // Write some initial data. 65 size_t size = sizeof(kMessage) - 1; 66 EXPECT_THAT(WriteFd(fd_, &kMessage, size), SyscallSucceedsWithValue(size)); 67 ASSERT_THAT(lseek(fd_, 0, SEEK_SET), SyscallSucceeds()); 68 69 // Map a useable buffer. 70 addr_ = mmap(0, 2 * kPageSize, PROT_READ | PROT_WRITE, 71 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 72 ASSERT_NE(addr_, MAP_FAILED); 73 char* buf = reinterpret_cast<char*>(addr_); 74 75 // Guard page for our read to run into. 76 ASSERT_THAT(mprotect(reinterpret_cast<void*>(buf + kPageSize), kPageSize, 77 PROT_NONE), 78 SyscallSucceeds()); 79 80 // Leave only one free byte in the buffer. 81 bad_buffer_ = buf + kPageSize - 1; 82 } 83 84 off_t Size() { 85 struct stat st; 86 int rc = fstat(fd_, &st); 87 if (rc < 0) { 88 return static_cast<off_t>(rc); 89 } 90 return st.st_size; 91 } 92 93 void TearDown() override { 94 EXPECT_THAT(munmap(addr_, 2 * kPageSize), SyscallSucceeds()) << addr_; 95 EXPECT_THAT(close(fd_), SyscallSucceeds()); 96 EXPECT_THAT(unlink(name_.c_str()), SyscallSucceeds()); 97 EXPECT_THAT(close(directory_fd_), SyscallSucceeds()); 98 } 99 100 // Return buffer with n bytes of free space. 101 // N.B. this is the same buffer used to back bad_buffer_. 102 char* FreeBytes(size_t n) { 103 TEST_CHECK(n <= static_cast<size_t>(4096)); 104 return reinterpret_cast<char*>(addr_) + kPageSize - n; 105 } 106 107 std::string name_; 108 int fd_; 109 TempPath directory_; 110 int directory_fd_; 111 void* addr_; 112 char* bad_buffer_; 113 }; 114 115 // We do both "big" and "small" tests to try to hit the "zero copy" and 116 // non-"zero copy" paths, which have different code paths for handling faults. 117 118 TEST_F(PartialBadBufferTest, ReadBig) { 119 EXPECT_THAT(RetryEINTR(read)(fd_, bad_buffer_, kPageSize), 120 SyscallSucceedsWithValue(1)); 121 EXPECT_EQ('h', bad_buffer_[0]); 122 } 123 124 TEST_F(PartialBadBufferTest, ReadSmall) { 125 EXPECT_THAT(RetryEINTR(read)(fd_, bad_buffer_, 10), 126 SyscallSucceedsWithValue(1)); 127 EXPECT_EQ('h', bad_buffer_[0]); 128 } 129 130 TEST_F(PartialBadBufferTest, PreadBig) { 131 EXPECT_THAT(RetryEINTR(pread)(fd_, bad_buffer_, kPageSize, 0), 132 SyscallSucceedsWithValue(1)); 133 EXPECT_EQ('h', bad_buffer_[0]); 134 } 135 136 TEST_F(PartialBadBufferTest, PreadSmall) { 137 EXPECT_THAT(RetryEINTR(pread)(fd_, bad_buffer_, 10, 0), 138 SyscallSucceedsWithValue(1)); 139 EXPECT_EQ('h', bad_buffer_[0]); 140 } 141 142 TEST_F(PartialBadBufferTest, ReadvBig) { 143 struct iovec vec; 144 vec.iov_base = bad_buffer_; 145 vec.iov_len = kPageSize; 146 147 EXPECT_THAT(RetryEINTR(readv)(fd_, &vec, 1), SyscallSucceedsWithValue(1)); 148 EXPECT_EQ('h', bad_buffer_[0]); 149 } 150 151 TEST_F(PartialBadBufferTest, ReadvSmall) { 152 struct iovec vec; 153 vec.iov_base = bad_buffer_; 154 vec.iov_len = 10; 155 156 EXPECT_THAT(RetryEINTR(readv)(fd_, &vec, 1), SyscallSucceedsWithValue(1)); 157 EXPECT_EQ('h', bad_buffer_[0]); 158 } 159 160 TEST_F(PartialBadBufferTest, PreadvBig) { 161 struct iovec vec; 162 vec.iov_base = bad_buffer_; 163 vec.iov_len = kPageSize; 164 165 EXPECT_THAT(RetryEINTR(preadv)(fd_, &vec, 1, 0), SyscallSucceedsWithValue(1)); 166 EXPECT_EQ('h', bad_buffer_[0]); 167 } 168 169 TEST_F(PartialBadBufferTest, PreadvSmall) { 170 struct iovec vec; 171 vec.iov_base = bad_buffer_; 172 vec.iov_len = 10; 173 174 EXPECT_THAT(RetryEINTR(preadv)(fd_, &vec, 1, 0), SyscallSucceedsWithValue(1)); 175 EXPECT_EQ('h', bad_buffer_[0]); 176 } 177 178 TEST_F(PartialBadBufferTest, WriteBig) { 179 off_t orig_size = Size(); 180 int n; 181 182 ASSERT_THAT(lseek(fd_, orig_size, SEEK_SET), SyscallSucceeds()); 183 EXPECT_THAT( 184 (n = RetryEINTR(write)(fd_, bad_buffer_, kPageSize)), 185 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 186 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 187 } 188 189 TEST_F(PartialBadBufferTest, WriteSmall) { 190 off_t orig_size = Size(); 191 int n; 192 193 ASSERT_THAT(lseek(fd_, orig_size, SEEK_SET), SyscallSucceeds()); 194 EXPECT_THAT( 195 (n = RetryEINTR(write)(fd_, bad_buffer_, 10)), 196 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 197 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 198 } 199 200 TEST_F(PartialBadBufferTest, PwriteBig) { 201 off_t orig_size = Size(); 202 int n; 203 204 EXPECT_THAT( 205 (n = RetryEINTR(pwrite)(fd_, bad_buffer_, kPageSize, orig_size)), 206 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 207 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 208 } 209 210 TEST_F(PartialBadBufferTest, PwriteSmall) { 211 off_t orig_size = Size(); 212 int n; 213 214 EXPECT_THAT( 215 (n = RetryEINTR(pwrite)(fd_, bad_buffer_, 10, orig_size)), 216 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 217 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 218 } 219 220 TEST_F(PartialBadBufferTest, WritevBig) { 221 struct iovec vec; 222 vec.iov_base = bad_buffer_; 223 vec.iov_len = kPageSize; 224 off_t orig_size = Size(); 225 int n; 226 227 ASSERT_THAT(lseek(fd_, orig_size, SEEK_SET), SyscallSucceeds()); 228 EXPECT_THAT( 229 (n = RetryEINTR(writev)(fd_, &vec, 1)), 230 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 231 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 232 } 233 234 TEST_F(PartialBadBufferTest, WritevSmall) { 235 struct iovec vec; 236 vec.iov_base = bad_buffer_; 237 vec.iov_len = 10; 238 off_t orig_size = Size(); 239 int n; 240 241 ASSERT_THAT(lseek(fd_, orig_size, SEEK_SET), SyscallSucceeds()); 242 EXPECT_THAT( 243 (n = RetryEINTR(writev)(fd_, &vec, 1)), 244 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 245 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 246 } 247 248 TEST_F(PartialBadBufferTest, PwritevBig) { 249 struct iovec vec; 250 vec.iov_base = bad_buffer_; 251 vec.iov_len = kPageSize; 252 off_t orig_size = Size(); 253 int n; 254 255 EXPECT_THAT( 256 (n = RetryEINTR(pwritev)(fd_, &vec, 1, orig_size)), 257 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 258 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 259 } 260 261 TEST_F(PartialBadBufferTest, PwritevSmall) { 262 struct iovec vec; 263 vec.iov_base = bad_buffer_; 264 vec.iov_len = 10; 265 off_t orig_size = Size(); 266 int n; 267 268 EXPECT_THAT( 269 (n = RetryEINTR(pwritev)(fd_, &vec, 1, orig_size)), 270 AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(1))); 271 EXPECT_EQ(Size(), orig_size + (n >= 0 ? n : 0)); 272 } 273 274 // getdents returns EFAULT when the you claim the buffer is large enough, but 275 // it actually isn't. 276 TEST_F(PartialBadBufferTest, GetdentsBig) { 277 EXPECT_THAT(RetryEINTR(syscall)(SYS_getdents64, directory_fd_, bad_buffer_, 278 kPageSize), 279 SyscallFailsWithErrno(EFAULT)); 280 } 281 282 // getdents returns EINVAL when the you claim the buffer is too small. 283 TEST_F(PartialBadBufferTest, GetdentsSmall) { 284 EXPECT_THAT( 285 RetryEINTR(syscall)(SYS_getdents64, directory_fd_, bad_buffer_, 10), 286 SyscallFailsWithErrno(EINVAL)); 287 } 288 289 // getdents will write entries into a buffer if there is space before it faults. 290 TEST_F(PartialBadBufferTest, GetdentsOneEntry) { 291 // 30 bytes is enough for one (small) entry. 292 char* buf = FreeBytes(30); 293 294 EXPECT_THAT( 295 RetryEINTR(syscall)(SYS_getdents64, directory_fd_, buf, kPageSize), 296 SyscallSucceedsWithValue(Gt(0))); 297 } 298 299 PosixErrorOr<sockaddr_storage> InetLoopbackAddr(int family) { 300 struct sockaddr_storage addr; 301 memset(&addr, 0, sizeof(addr)); 302 addr.ss_family = family; 303 switch (family) { 304 case AF_INET: 305 reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr.s_addr = 306 htonl(INADDR_LOOPBACK); 307 break; 308 case AF_INET6: 309 reinterpret_cast<struct sockaddr_in6*>(&addr)->sin6_addr = 310 in6addr_loopback; 311 break; 312 default: 313 return PosixError(EINVAL, 314 absl::StrCat("unknown socket family: ", family)); 315 } 316 return addr; 317 } 318 319 // SendMsgTCP verifies that calling sendmsg with a bad address returns an 320 // EFAULT. It also verifies that passing a buffer which is made up of 2 321 // pages one valid and one guard page succeeds as long as the write is 322 // for exactly the size of 1 page. 323 TEST_F(PartialBadBufferTest, SendMsgTCP) { 324 // FIXME(b/171436815): Netstack save/restore is broken. 325 const DisableSave ds; 326 327 auto listen_socket = 328 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); 329 330 // Initialize address to the loopback one. 331 sockaddr_storage addr = ASSERT_NO_ERRNO_AND_VALUE(InetLoopbackAddr(AF_INET)); 332 socklen_t addrlen = sizeof(addr); 333 334 // Bind to some port then start listening. 335 ASSERT_THAT(bind(listen_socket.get(), 336 reinterpret_cast<struct sockaddr*>(&addr), addrlen), 337 SyscallSucceeds()); 338 339 ASSERT_THAT(listen(listen_socket.get(), SOMAXCONN), SyscallSucceeds()); 340 341 // Get the address we're listening on, then connect to it. We need to do this 342 // because we're allowing the stack to pick a port for us. 343 ASSERT_THAT(getsockname(listen_socket.get(), 344 reinterpret_cast<struct sockaddr*>(&addr), &addrlen), 345 SyscallSucceeds()); 346 347 auto send_socket = 348 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); 349 350 ASSERT_THAT( 351 RetryEINTR(connect)(send_socket.get(), 352 reinterpret_cast<struct sockaddr*>(&addr), addrlen), 353 SyscallSucceeds()); 354 355 // Accept the connection. 356 auto recv_socket = 357 ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_socket.get(), nullptr, nullptr)); 358 359 // TODO(gvisor.dev/issue/674): Update this once Netstack matches linux 360 // behaviour on a setsockopt of SO_RCVBUF/SO_SNDBUF. 361 // 362 // Set SO_SNDBUF for socket to exactly kPageSize+1. 363 // 364 // gVisor does not double the value passed in SO_SNDBUF like linux does so we 365 // just increase it by 1 byte here for gVisor so that we can test writing 1 366 // byte past the valid page and check that it triggers an EFAULT 367 // correctly. Otherwise in gVisor the sendmsg call will just return with no 368 // error with kPageSize bytes written successfully. 369 const uint32_t buf_size = kPageSize + 1; 370 ASSERT_THAT(setsockopt(send_socket.get(), SOL_SOCKET, SO_SNDBUF, &buf_size, 371 sizeof(buf_size)), 372 SyscallSucceedsWithValue(0)); 373 374 struct msghdr hdr = {}; 375 struct iovec iov = {}; 376 iov.iov_base = bad_buffer_; 377 iov.iov_len = kPageSize; 378 hdr.msg_iov = &iov; 379 hdr.msg_iovlen = 1; 380 381 ASSERT_THAT(RetryEINTR(sendmsg)(send_socket.get(), &hdr, 0), 382 SyscallFailsWithErrno(EFAULT)); 383 384 // Now assert that writing kPageSize from addr_ succeeds. 385 iov.iov_base = addr_; 386 ASSERT_THAT(RetryEINTR(sendmsg)(send_socket.get(), &hdr, 0), 387 SyscallSucceedsWithValue(kPageSize)); 388 // Read all the data out so that we drain the socket SND_BUF on the sender. 389 std::vector<char> buffer(kPageSize); 390 ASSERT_THAT(RetryEINTR(read)(recv_socket.get(), buffer.data(), kPageSize), 391 SyscallSucceedsWithValue(kPageSize)); 392 393 // Sleep for a shortwhile to ensure that we have time to process the 394 // ACKs. This is not strictly required unless running under gotsan which is a 395 // lot slower and can result in the next write to write only 1 byte instead of 396 // our intended kPageSize + 1. 397 absl::SleepFor(absl::Milliseconds(50)); 398 399 // Now assert that writing > kPageSize results in EFAULT. 400 iov.iov_len = kPageSize + 1; 401 ASSERT_THAT(RetryEINTR(sendmsg)(send_socket.get(), &hdr, 0), 402 SyscallFailsWithErrno(EFAULT)); 403 } 404 405 } // namespace 406 407 } // namespace testing 408 } // namespace gvisor