github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/truncate.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 <signal.h> 17 #include <sys/resource.h> 18 #include <sys/stat.h> 19 #include <sys/vfs.h> 20 #include <time.h> 21 #include <unistd.h> 22 23 #include <iostream> 24 #include <string> 25 26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 28 #include "absl/strings/string_view.h" 29 #include "test/syscalls/linux/file_base.h" 30 #include "test/util/capability_util.h" 31 #include "test/util/cleanup.h" 32 #include "test/util/file_descriptor.h" 33 #include "test/util/temp_path.h" 34 #include "test/util/test_util.h" 35 36 namespace gvisor { 37 namespace testing { 38 39 namespace { 40 41 class FixtureTruncateTest : public FileTest { 42 void SetUp() override { FileTest::SetUp(); } 43 }; 44 45 TEST_F(FixtureTruncateTest, Truncate) { 46 // Get the current rlimit and restore after test run. 47 struct rlimit initial_lim; 48 ASSERT_THAT(getrlimit(RLIMIT_FSIZE, &initial_lim), SyscallSucceeds()); 49 auto cleanup = Cleanup([&initial_lim] { 50 EXPECT_THAT(setrlimit(RLIMIT_FSIZE, &initial_lim), SyscallSucceeds()); 51 }); 52 53 // Check that it starts at size zero. 54 struct stat buf; 55 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 56 EXPECT_EQ(buf.st_size, 0); 57 58 // Stay at size zero. 59 EXPECT_THAT(truncate(test_file_name_.c_str(), 0), SyscallSucceeds()); 60 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 61 EXPECT_EQ(buf.st_size, 0); 62 63 // Grow to ten bytes. 64 EXPECT_THAT(truncate(test_file_name_.c_str(), 10), SyscallSucceeds()); 65 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 66 EXPECT_EQ(buf.st_size, 10); 67 68 // Can't be truncated to a negative number. 69 EXPECT_THAT(truncate(test_file_name_.c_str(), -1), 70 SyscallFailsWithErrno(EINVAL)); 71 72 // Try growing past the file size limit. 73 sigset_t new_mask; 74 sigemptyset(&new_mask); 75 sigaddset(&new_mask, SIGXFSZ); 76 sigprocmask(SIG_BLOCK, &new_mask, nullptr); 77 struct timespec timelimit; 78 timelimit.tv_sec = 10; 79 timelimit.tv_nsec = 0; 80 81 struct rlimit setlim; 82 setlim.rlim_cur = 1024; 83 setlim.rlim_max = RLIM_INFINITY; 84 ASSERT_THAT(setrlimit(RLIMIT_FSIZE, &setlim), SyscallSucceeds()); 85 EXPECT_THAT(truncate(test_file_name_.c_str(), 1025), 86 SyscallFailsWithErrno(EFBIG)); 87 EXPECT_EQ(sigtimedwait(&new_mask, nullptr, &timelimit), SIGXFSZ); 88 ASSERT_THAT(sigprocmask(SIG_UNBLOCK, &new_mask, nullptr), SyscallSucceeds()); 89 90 // Shrink back down to zero. 91 EXPECT_THAT(truncate(test_file_name_.c_str(), 0), SyscallSucceeds()); 92 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 93 EXPECT_EQ(buf.st_size, 0); 94 } 95 96 TEST_F(FixtureTruncateTest, Ftruncate) { 97 // Get the current rlimit and restore after test run. 98 struct rlimit initial_lim; 99 ASSERT_THAT(getrlimit(RLIMIT_FSIZE, &initial_lim), SyscallSucceeds()); 100 auto cleanup = Cleanup([&initial_lim] { 101 EXPECT_THAT(setrlimit(RLIMIT_FSIZE, &initial_lim), SyscallSucceeds()); 102 }); 103 104 // Check that it starts at size zero. 105 struct stat buf; 106 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 107 EXPECT_EQ(buf.st_size, 0); 108 109 // Stay at size zero. 110 EXPECT_THAT(ftruncate(test_file_fd_.get(), 0), SyscallSucceeds()); 111 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 112 EXPECT_EQ(buf.st_size, 0); 113 114 // Grow to ten bytes. 115 EXPECT_THAT(ftruncate(test_file_fd_.get(), 10), SyscallSucceeds()); 116 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 117 EXPECT_EQ(buf.st_size, 10); 118 119 // Can't be truncated to a negative number. 120 EXPECT_THAT(ftruncate(test_file_fd_.get(), -1), 121 SyscallFailsWithErrno(EINVAL)); 122 123 // Try growing past the file size limit. 124 sigset_t new_mask; 125 sigemptyset(&new_mask); 126 sigaddset(&new_mask, SIGXFSZ); 127 sigprocmask(SIG_BLOCK, &new_mask, nullptr); 128 struct timespec timelimit; 129 timelimit.tv_sec = 10; 130 timelimit.tv_nsec = 0; 131 132 struct rlimit setlim; 133 setlim.rlim_cur = 1024; 134 setlim.rlim_max = RLIM_INFINITY; 135 ASSERT_THAT(setrlimit(RLIMIT_FSIZE, &setlim), SyscallSucceeds()); 136 EXPECT_THAT(ftruncate(test_file_fd_.get(), 1025), 137 SyscallFailsWithErrno(EFBIG)); 138 EXPECT_EQ(sigtimedwait(&new_mask, nullptr, &timelimit), SIGXFSZ); 139 ASSERT_THAT(sigprocmask(SIG_UNBLOCK, &new_mask, nullptr), SyscallSucceeds()); 140 141 // Shrink back down to zero. 142 EXPECT_THAT(ftruncate(test_file_fd_.get(), 0), SyscallSucceeds()); 143 ASSERT_THAT(fstat(test_file_fd_.get(), &buf), SyscallSucceeds()); 144 EXPECT_EQ(buf.st_size, 0); 145 } 146 147 // Truncating a file down clears that portion of the file. 148 TEST_F(FixtureTruncateTest, FtruncateShrinkGrow) { 149 std::vector<char> buf(10, 'a'); 150 EXPECT_THAT(WriteFd(test_file_fd_.get(), buf.data(), buf.size()), 151 SyscallSucceedsWithValue(buf.size())); 152 153 // Shrink then regrow the file. This should clear the second half of the file. 154 EXPECT_THAT(ftruncate(test_file_fd_.get(), 5), SyscallSucceeds()); 155 EXPECT_THAT(ftruncate(test_file_fd_.get(), 10), SyscallSucceeds()); 156 157 EXPECT_THAT(lseek(test_file_fd_.get(), 0, SEEK_SET), SyscallSucceeds()); 158 159 std::vector<char> buf2(10); 160 EXPECT_THAT(ReadFd(test_file_fd_.get(), buf2.data(), buf2.size()), 161 SyscallSucceedsWithValue(buf2.size())); 162 163 std::vector<char> expect = {'a', 'a', 'a', 'a', 'a', 164 '\0', '\0', '\0', '\0', '\0'}; 165 EXPECT_EQ(expect, buf2); 166 } 167 168 TEST(TruncateTest, TruncateDir) { 169 auto temp_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 170 EXPECT_THAT(truncate(temp_dir.path().c_str(), 0), 171 SyscallFailsWithErrno(EISDIR)); 172 } 173 174 TEST(TruncateTest, FtruncateDir) { 175 auto temp_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 176 const FileDescriptor fd = 177 ASSERT_NO_ERRNO_AND_VALUE(Open(temp_dir.path(), O_DIRECTORY | O_RDONLY)); 178 EXPECT_THAT(ftruncate(fd.get(), 0), SyscallFailsWithErrno(EINVAL)); 179 } 180 181 TEST(TruncateTest, TruncateNonWriteable) { 182 // Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to 183 // always override write permissions. 184 AutoCapability cap(CAP_DAC_OVERRIDE, false); 185 auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 186 GetAbsoluteTestTmpdir(), absl::string_view(), 0555 /* mode */)); 187 EXPECT_THAT(truncate(temp_file.path().c_str(), 0), 188 SyscallFailsWithErrno(EACCES)); 189 } 190 191 TEST(TruncateTest, FtruncateNonWriteable) { 192 auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 193 GetAbsoluteTestTmpdir(), absl::string_view(), 0555 /* mode */)); 194 const FileDescriptor fd = 195 ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_RDONLY)); 196 EXPECT_THAT(ftruncate(fd.get(), 0), SyscallFailsWithErrno(EINVAL)); 197 } 198 199 TEST(TruncateTest, FtruncateWithOpath) { 200 SKIP_IF(IsRunningWithVFS1()); 201 auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 202 GetAbsoluteTestTmpdir(), absl::string_view(), 0555 /* mode */)); 203 const FileDescriptor fd = 204 ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_PATH)); 205 EXPECT_THAT(ftruncate(fd.get(), 0), AnyOf(SyscallFailsWithErrno(EBADF), 206 SyscallFailsWithErrno(EINVAL))); 207 } 208 209 // ftruncate(2) should succeed as long as the file descriptor is writeable, 210 // regardless of whether the file permissions allow writing. 211 TEST(TruncateTest, FtruncateWithoutWritePermission) { 212 // Drop capabilities that allow us to override file permissions. 213 AutoCapability cap(CAP_DAC_OVERRIDE, false); 214 215 // The only time we can open a file with flags forbidden by its permissions 216 // is when we are creating the file. We cannot re-open with the same flags, 217 // so we cannot restore an fd obtained from such an operation. 218 const DisableSave ds; 219 auto path = NewTempAbsPath(); 220 const FileDescriptor fd = 221 ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_RDWR | O_CREAT, 0444)); 222 223 // In goferfs, ftruncate may be converted to a remote truncate operation that 224 // unavoidably requires write permission. 225 SKIP_IF(IsRunningOnGvisor() && !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(path))); 226 ASSERT_THAT(ftruncate(fd.get(), 100), SyscallSucceeds()); 227 } 228 229 TEST(TruncateTest, TruncateNonExist) { 230 EXPECT_THAT(truncate("/foo/bar", 0), SyscallFailsWithErrno(ENOENT)); 231 } 232 233 TEST(TruncateTest, FtruncateVirtualTmp) { 234 auto temp_file = NewTempAbsPathInDir("/dev/shm"); 235 const DisableSave ds; // Incompatible permissions. 236 const FileDescriptor fd = 237 ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file, O_RDWR | O_CREAT | O_EXCL, 0)); 238 EXPECT_THAT(ftruncate(fd.get(), 100), SyscallSucceeds()); 239 } 240 241 // NOTE: There are additional truncate(2)/ftruncate(2) tests in mknod.cc 242 // which are there to avoid running the tests on a number of different 243 // filesystems which may not support mknod. 244 245 } // namespace 246 247 } // namespace testing 248 } // namespace gvisor