gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/close_range.cc (about) 1 // Copyright 2022 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 <asm-generic/errno-base.h> 16 #include <unistd.h> 17 18 #include <vector> 19 20 #include "gtest/gtest.h" 21 #include "absl/base/macros.h" 22 #include "test/util/file_descriptor.h" 23 #include "test/util/posix_error.h" 24 #include "test/util/temp_path.h" 25 #include "test/util/test_util.h" 26 #include "test/util/thread_util.h" 27 28 namespace gvisor { 29 namespace testing { 30 31 namespace { 32 33 #ifndef CLOSE_RANGE_UNSHARE 34 #define CLOSE_RANGE_UNSHARE (1U << 1) 35 #endif 36 #ifndef CLOSE_RANGE_CLOEXEC 37 #define CLOSE_RANGE_CLOEXEC (1U << 2) 38 #endif 39 40 #ifndef SYS_close_range 41 #if defined(__x86_64__) || defined(__aarch64__) 42 #define SYS_close_range 436 43 #else 44 #error "Unknown architecture" 45 #endif 46 #endif // SYS_close_range 47 48 int close_range(unsigned int first, unsigned int last, unsigned int flags) { 49 return syscall(SYS_close_range, first, last, flags); 50 } 51 52 class CloseRangeTest : public ::testing::Test { 53 public: 54 void CreateFiles(int num_files) { 55 file_names_.reserve(num_files); 56 for (int i = 0; i < num_files; ++i) { 57 file_names_.push_back(NewTempAbsPath()); 58 int fd; 59 ASSERT_THAT(fd = open(file_names_[i].c_str(), O_CREAT, 0644), 60 SyscallSucceeds()); 61 ASSERT_THAT(close(fd), SyscallSucceeds()); 62 } 63 } 64 65 void OpenFilesRdwr() { 66 fds_.clear(); 67 fds_.reserve(file_names_.size()); 68 for (std::string &file_name : file_names_) { 69 int fd; 70 ASSERT_THAT(fd = open(file_name.c_str(), O_RDWR), SyscallSucceeds()); 71 fds_.push_back(fd); 72 } 73 } 74 75 private: 76 void TearDown() override { 77 for (std::string &name : file_names_) { 78 unlink(name.c_str()); 79 } 80 } 81 82 protected: 83 std::vector<std::string> file_names_; 84 std::vector<unsigned int> fds_; 85 }; 86 87 // Base test to confirm that all files in contiguous range get closed. 88 TEST_F(CloseRangeTest, ContiguousRange) { 89 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 90 int num_files_in_range = 10; 91 unsigned int flags = 0; 92 93 CreateFiles(num_files_in_range); 94 OpenFilesRdwr(); 95 96 for (int fd : fds_) { 97 auto ret = ReadAllFd(fd); 98 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 99 } 100 101 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 102 SyscallSucceeds()); 103 for (int fd : fds_) { 104 auto ret = ReadAllFd(fd); 105 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 106 } 107 } 108 109 // Test to confirm that a range with files already closed in the range still 110 // closes the remaining files. 111 TEST_F(CloseRangeTest, RangeWithHoles) { 112 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 113 int num_files_in_range = 10; 114 unsigned int flags = 0; 115 116 CreateFiles(num_files_in_range); 117 OpenFilesRdwr(); 118 119 for (int fd : fds_) { 120 auto ret = ReadAllFd(fd); 121 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 122 } 123 124 EXPECT_THAT(close(fds_[2]), SyscallSucceeds()); 125 EXPECT_THAT(close(fds_[7]), SyscallSucceeds()); 126 127 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 128 SyscallSucceeds()); 129 for (int fd : fds_) { 130 auto ret = ReadAllFd(fd); 131 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 132 } 133 } 134 135 // Test to confirm that closing a range with fds preceding and following the 136 // range leaves those other fds open. 137 TEST_F(CloseRangeTest, RangeInMiddleOfOpenFiles) { 138 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 139 int num_files_in_range = 10; 140 unsigned int flags = 0; 141 142 CreateFiles(num_files_in_range); 143 OpenFilesRdwr(); 144 145 for (int fd : fds_) { 146 auto ret = ReadAllFd(fd); 147 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 148 } 149 150 size_t slice_start = 4; 151 size_t slice_end = 7; 152 EXPECT_THAT(close_range(fds_[slice_start], fds_[slice_end], flags), 153 SyscallSucceeds()); 154 for (int fd : 155 std::vector(fds_.begin() + slice_start, fds_.begin() + slice_end + 1)) { 156 auto ret = ReadAllFd(fd); 157 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 158 } 159 for (int fd : std::vector(fds_.begin(), fds_.begin() + slice_start)) { 160 auto ret = ReadAllFd(fd); 161 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 162 } 163 for (int fd : std::vector(fds_.begin() + slice_end + 1, fds_.end())) { 164 auto ret = ReadAllFd(fd); 165 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 166 } 167 } 168 169 // Test to confirm that calling close_range on just one file succeeds. 170 TEST_F(CloseRangeTest, SingleFile) { 171 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 172 int num_files_in_range = 1; 173 unsigned int flags = 0; /* */ 174 175 CreateFiles(num_files_in_range); 176 OpenFilesRdwr(); 177 178 auto ret = ReadAllFd(fds_[0]); 179 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 180 181 EXPECT_THAT(close_range(fds_[0], fds_[0], flags), SyscallSucceeds()); 182 183 ret = ReadAllFd(fds_[0]); 184 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 185 } 186 187 // Test to confirm that calling close_range twice on the same range does not 188 // cause errors. 189 TEST_F(CloseRangeTest, CallCloseRangeTwice) { 190 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 191 int num_files_in_range = 10; 192 unsigned int flags = 0; 193 194 CreateFiles(num_files_in_range); 195 OpenFilesRdwr(); 196 197 for (int fd : fds_) { 198 auto ret = ReadAllFd(fd); 199 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 200 } 201 202 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 203 SyscallSucceeds()); 204 for (int fd : fds_) { 205 auto ret = ReadAllFd(fd); 206 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 207 } 208 209 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 210 SyscallSucceeds()); 211 } 212 213 // Test that using CLOEXEC flag does not close the file for this process. 214 TEST_F(CloseRangeTest, CloexecFlagTest) { 215 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 216 int num_files_in_range = 10; 217 unsigned int flags = CLOSE_RANGE_CLOEXEC; 218 219 // CLOEXEC is only available on >=5.11 kernels. 220 SKIP_IF(close_range(1, 0, flags) < 0 && errno == EINVAL); 221 222 CreateFiles(num_files_in_range); 223 OpenFilesRdwr(); 224 225 for (int fd : fds_) { 226 auto ret = ReadAllFd(fd); 227 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 228 } 229 230 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 231 SyscallSucceeds()); 232 for (int fd : fds_) { 233 auto ret = ReadAllFd(fd); 234 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 235 } 236 } 237 238 // Test that using UNSHARE flag still properly closes the files. 239 TEST_F(CloseRangeTest, UnshareFlagTest) { 240 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 241 int num_files_in_range = 10; 242 unsigned int flags = CLOSE_RANGE_UNSHARE; 243 244 CreateFiles(num_files_in_range); 245 OpenFilesRdwr(); 246 247 for (int fd : fds_) { 248 auto ret = ReadAllFd(fd); 249 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 250 } 251 252 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 253 SyscallSucceeds()); 254 for (int fd : fds_) { 255 auto ret = ReadAllFd(fd); 256 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 257 } 258 } 259 260 // Test that using the UNSHARE flag and closing files at the start of the range 261 // still leaves the latter files opened. 262 TEST_F(CloseRangeTest, UnshareFlagAndCloseRangeAtStart) { 263 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 264 int num_files_in_range = 10; 265 unsigned int flags = CLOSE_RANGE_UNSHARE; 266 267 CreateFiles(num_files_in_range); 268 OpenFilesRdwr(); 269 270 for (int fd : fds_) { 271 auto ret = ReadAllFd(fd); 272 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 273 } 274 275 size_t range_split = 5; 276 EXPECT_THAT(close_range(fds_[0], fds_[range_split - 1], flags), 277 SyscallSucceeds()); 278 for (int fd : std::vector(fds_.begin(), fds_.begin() + range_split)) { 279 auto ret = ReadAllFd(fd); 280 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 281 } 282 for (int fd : std::vector(fds_.begin() + range_split, fds_.end())) { 283 auto ret = ReadAllFd(fd); 284 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 285 } 286 } 287 288 // Test that using the UNSHARE flag and closing files at the end of the range 289 // still leaves the earlier files opened. 290 TEST_F(CloseRangeTest, UnshareFlagAndCloseRangeAtEnd) { 291 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 292 int num_files_in_range = 10; 293 unsigned int flags = CLOSE_RANGE_UNSHARE; 294 295 CreateFiles(num_files_in_range); 296 OpenFilesRdwr(); 297 298 for (int fd : fds_) { 299 auto ret = ReadAllFd(fd); 300 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 301 } 302 303 size_t range_split = 5; 304 EXPECT_THAT( 305 close_range(fds_[range_split], fds_[num_files_in_range - 1], flags), 306 SyscallSucceeds()); 307 for (int fd : std::vector(fds_.begin(), fds_.begin() + range_split)) { 308 auto ret = ReadAllFd(fd); 309 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 310 } 311 for (int fd : std::vector(fds_.begin() + range_split, fds_.end())) { 312 auto ret = ReadAllFd(fd); 313 EXPECT_THAT(ret, PosixErrorIs(EBADF)); 314 } 315 } 316 317 // Test that using both CLOEXEC and UNSHARE flags does not close files for this 318 // process. 319 TEST_F(CloseRangeTest, CloexecAndUnshareFlagTest) { 320 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 321 int num_files_in_range = 10; 322 unsigned int flags = CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE; 323 324 // CLOEXEC is only available on >=5.11 kernels. 325 SKIP_IF(close_range(1, 0, flags) < 0 && errno == EINVAL); 326 327 CreateFiles(num_files_in_range); 328 OpenFilesRdwr(); 329 330 for (int fd : fds_) { 331 auto ret = ReadAllFd(fd); 332 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 333 } 334 335 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 336 SyscallSucceeds()); 337 for (int fd : fds_) { 338 auto ret = ReadAllFd(fd); 339 EXPECT_THAT(ret, IsPosixErrorOkMatcher()); 340 } 341 } 342 343 // Test that calling with invalid range does not succeed. 344 TEST_F(CloseRangeTest, RangeFirstGreaterThanLast) { 345 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 346 int num_files_in_range = 10; 347 unsigned int flags = 0; 348 349 CreateFiles(num_files_in_range); 350 OpenFilesRdwr(); 351 352 EXPECT_THAT(close_range(fds_[num_files_in_range - 1], fds_[0], flags), 353 SyscallFailsWithErrno(EINVAL)); 354 } 355 356 // Test that calling with invalid flags does not succeed. 357 TEST_F(CloseRangeTest, InvalidFlags) { 358 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 359 int num_files_in_range = 10; 360 361 CreateFiles(num_files_in_range); 362 OpenFilesRdwr(); 363 364 unsigned int flags = CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE | 0xF; 365 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 366 SyscallFailsWithErrno(EINVAL)); 367 368 flags = 0xF0; 369 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 370 SyscallFailsWithErrno(EINVAL)); 371 372 flags = CLOSE_RANGE_CLOEXEC | 0xF00; 373 EXPECT_THAT(close_range(fds_[0], fds_[num_files_in_range - 1], flags), 374 SyscallFailsWithErrno(EINVAL)); 375 } 376 377 // Test that calling close_range concurrently while creating new files yields 378 // expected results. 379 TEST_F(CloseRangeTest, ConcurrentCalls) { 380 SKIP_IF(!IsRunningOnGvisor() && close_range(1, 0, 0) < 0 && errno == ENOSYS); 381 const int num_files_in_range = 10; 382 const unsigned int flags = CLOSE_RANGE_UNSHARE; 383 const int num_threads = 100; 384 std::unique_ptr<ScopedThread> threads[num_threads]; 385 386 CreateFiles(num_files_in_range); 387 OpenFilesRdwr(); 388 389 auto cr_call = []() { 390 EXPECT_THAT(close_range(num_files_in_range / 2, 391 num_files_in_range + num_threads, flags), 392 SyscallSucceeds()); 393 }; 394 auto open_file_call = []() { 395 auto file = NewTempAbsPath(); 396 EXPECT_THAT(open(file.c_str(), O_CREAT, 0644), SyscallSucceeds()); 397 }; 398 399 for (int i = 0; i < num_threads; i++) { 400 if (i % 2 == 0) { 401 threads[i] = std::make_unique<ScopedThread>(cr_call); 402 } else { 403 threads[i] = std::make_unique<ScopedThread>(open_file_call); 404 } 405 } 406 } 407 408 } // namespace 409 410 } // namespace testing 411 } // namespace gvisor