gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/read.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 <fcntl.h> 16 #include <sys/mman.h> 17 #include <unistd.h> 18 19 #include <vector> 20 21 #include "gtest/gtest.h" 22 #include "absl/base/macros.h" 23 #include "test/util/cleanup.h" 24 #include "test/util/file_descriptor.h" 25 #include "test/util/temp_path.h" 26 #include "test/util/test_util.h" 27 28 namespace gvisor { 29 namespace testing { 30 31 namespace { 32 33 class ReadTest : public ::testing::Test { 34 void SetUp() override { 35 name_ = NewTempAbsPath(); 36 int fd; 37 ASSERT_THAT(fd = open(name_.c_str(), O_CREAT, 0644), SyscallSucceeds()); 38 ASSERT_THAT(close(fd), SyscallSucceeds()); 39 } 40 41 void TearDown() override { unlink(name_.c_str()); } 42 43 public: 44 std::string name_; 45 }; 46 47 TEST_F(ReadTest, ZeroBuffer) { 48 int fd; 49 ASSERT_THAT(fd = open(name_.c_str(), O_RDWR), SyscallSucceeds()); 50 51 char msg[] = "hello world"; 52 EXPECT_THAT(PwriteFd(fd, msg, strlen(msg), 0), 53 SyscallSucceedsWithValue(strlen(msg))); 54 55 char buf[10]; 56 EXPECT_THAT(ReadFd(fd, buf, 0), SyscallSucceedsWithValue(0)); 57 EXPECT_THAT(close(fd), SyscallSucceeds()); 58 } 59 60 TEST_F(ReadTest, EmptyFileReturnsZeroAtEOF) { 61 int fd; 62 ASSERT_THAT(fd = open(name_.c_str(), O_RDWR), SyscallSucceeds()); 63 64 char eof_buf[10]; 65 EXPECT_THAT(ReadFd(fd, eof_buf, 10), SyscallSucceedsWithValue(0)); 66 EXPECT_THAT(close(fd), SyscallSucceeds()); 67 } 68 69 TEST_F(ReadTest, EofAfterRead) { 70 int fd; 71 ASSERT_THAT(fd = open(name_.c_str(), O_RDWR), SyscallSucceeds()); 72 73 // Write some bytes to be read. 74 constexpr char kMessage[] = "hello world"; 75 EXPECT_THAT(PwriteFd(fd, kMessage, sizeof(kMessage), 0), 76 SyscallSucceedsWithValue(sizeof(kMessage))); 77 78 // Read all of the bytes at once. 79 char buf[sizeof(kMessage)]; 80 EXPECT_THAT(ReadFd(fd, buf, sizeof(kMessage)), 81 SyscallSucceedsWithValue(sizeof(kMessage))); 82 83 // Read again with a non-zero buffer and expect EOF. 84 char eof_buf[10]; 85 EXPECT_THAT(ReadFd(fd, eof_buf, 10), SyscallSucceedsWithValue(0)); 86 EXPECT_THAT(close(fd), SyscallSucceeds()); 87 } 88 89 TEST_F(ReadTest, DevNullReturnsEof) { 90 int fd; 91 ASSERT_THAT(fd = open("/dev/null", O_RDONLY), SyscallSucceeds()); 92 std::vector<char> buf(1); 93 EXPECT_THAT(ReadFd(fd, buf.data(), 1), SyscallSucceedsWithValue(0)); 94 EXPECT_THAT(close(fd), SyscallSucceeds()); 95 } 96 97 const int kReadSize = 128 * 1024; 98 99 // Do not allow random save as it could lead to partial reads. 100 TEST_F(ReadTest, CanReadFullyFromDevZero) { 101 int fd; 102 ASSERT_THAT(fd = open("/dev/zero", O_RDONLY), SyscallSucceeds()); 103 104 std::vector<char> buf(kReadSize, 1); 105 EXPECT_THAT(ReadFd(fd, buf.data(), kReadSize), 106 SyscallSucceedsWithValue(kReadSize)); 107 EXPECT_THAT(close(fd), SyscallSucceeds()); 108 EXPECT_EQ(std::vector<char>(kReadSize, 0), buf); 109 } 110 111 TEST_F(ReadTest, ReadDirectoryFails) { 112 const FileDescriptor file = 113 ASSERT_NO_ERRNO_AND_VALUE(Open(GetAbsoluteTestTmpdir(), O_RDONLY)); 114 std::vector<char> buf(1); 115 EXPECT_THAT(ReadFd(file.get(), buf.data(), 1), SyscallFailsWithErrno(EISDIR)); 116 } 117 118 TEST_F(ReadTest, ReadWithOpath) { 119 const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 120 const FileDescriptor fd = 121 ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_PATH)); 122 std::vector<char> buf(1); 123 EXPECT_THAT(ReadFd(fd.get(), buf.data(), 1), SyscallFailsWithErrno(EBADF)); 124 } 125 126 // Test that partial writes that hit SIGSEGV are correctly handled and return 127 // partial write. 128 TEST_F(ReadTest, PartialReadSIGSEGV) { 129 // Allocate 2 pages and remove permission from the second. 130 const size_t size = 2 * kPageSize; 131 void* addr = 132 mmap(0, size, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 133 ASSERT_NE(addr, MAP_FAILED); 134 auto cleanup = Cleanup( 135 [addr, size] { EXPECT_THAT(munmap(addr, size), SyscallSucceeds()); }); 136 137 FileDescriptor fd = 138 ASSERT_NO_ERRNO_AND_VALUE(Open(name_.c_str(), O_RDWR, 0666)); 139 for (size_t i = 0; i < 2; i++) { 140 EXPECT_THAT(pwrite(fd.get(), addr, size, 0), 141 SyscallSucceedsWithValue(size)); 142 } 143 144 void* badAddr = reinterpret_cast<char*>(addr) + kPageSize; 145 ASSERT_THAT(mprotect(badAddr, kPageSize, PROT_NONE), SyscallSucceeds()); 146 147 // Attempt to read to both pages. Create a non-contiguous iovec pair to 148 // ensure operation is done in 2 steps. 149 struct iovec iov[] = { 150 { 151 .iov_base = addr, 152 .iov_len = kPageSize, 153 }, 154 { 155 .iov_base = addr, 156 .iov_len = size, 157 }, 158 }; 159 EXPECT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallSucceeds()); 160 EXPECT_THAT(readv(fd.get(), iov, ABSL_ARRAYSIZE(iov)), 161 SyscallSucceedsWithValue(size)); 162 } 163 164 } // namespace 165 166 } // namespace testing 167 } // namespace gvisor