github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/rename.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 <stdio.h> 17 18 #include <string> 19 20 #include "gtest/gtest.h" 21 #include "absl/strings/string_view.h" 22 #include "test/util/capability_util.h" 23 #include "test/util/cleanup.h" 24 #include "test/util/file_descriptor.h" 25 #include "test/util/fs_util.h" 26 #include "test/util/temp_path.h" 27 #include "test/util/test_util.h" 28 29 using ::testing::AnyOf; 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 TEST(RenameTest, RootToAnything) { 37 ASSERT_THAT(rename("/", "/bin"), SyscallFailsWithErrno(EBUSY)); 38 } 39 40 TEST(RenameTest, AnythingToRoot) { 41 ASSERT_THAT(rename("/bin", "/"), SyscallFailsWithErrno(EBUSY)); 42 } 43 44 TEST(RenameTest, SourceIsAncestorOfTarget) { 45 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 46 auto subdir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 47 ASSERT_THAT(rename(dir.path().c_str(), subdir.path().c_str()), 48 SyscallFailsWithErrno(EINVAL)); 49 50 // Try an even deeper directory. 51 auto deep_subdir = 52 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(subdir.path())); 53 ASSERT_THAT(rename(dir.path().c_str(), deep_subdir.path().c_str()), 54 SyscallFailsWithErrno(EINVAL)); 55 } 56 57 TEST(RenameTest, TargetIsAncestorOfSource) { 58 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 59 auto subdir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path())); 60 ASSERT_THAT(rename(subdir.path().c_str(), dir.path().c_str()), 61 SyscallFailsWithErrno(ENOTEMPTY)); 62 63 // Try an even deeper directory. 64 auto deep_subdir = 65 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(subdir.path())); 66 ASSERT_THAT(rename(deep_subdir.path().c_str(), dir.path().c_str()), 67 SyscallFailsWithErrno(ENOTEMPTY)); 68 } 69 70 TEST(RenameTest, FileToSelf) { 71 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 72 EXPECT_THAT(rename(f.path().c_str(), f.path().c_str()), SyscallSucceeds()); 73 } 74 75 TEST(RenameTest, DirectoryToSelf) { 76 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 77 EXPECT_THAT(rename(f.path().c_str(), f.path().c_str()), SyscallSucceeds()); 78 } 79 80 TEST(RenameTest, FileToSameDirectory) { 81 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 82 std::string const newpath = NewTempAbsPath(); 83 ASSERT_THAT(rename(f.path().c_str(), newpath.c_str()), SyscallSucceeds()); 84 std::string const oldpath = f.release(); 85 f.reset(newpath); 86 EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false)); 87 EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true)); 88 } 89 90 TEST(RenameTest, DirectoryToSameDirectory) { 91 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 92 std::string const newpath = NewTempAbsPath(); 93 ASSERT_THAT(rename(dir.path().c_str(), newpath.c_str()), SyscallSucceeds()); 94 std::string const oldpath = dir.release(); 95 dir.reset(newpath); 96 EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false)); 97 EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true)); 98 } 99 100 TEST(RenameTest, FileToParentDirectory) { 101 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 102 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 103 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir2.path())); 104 std::string const newpath = NewTempAbsPathInDir(dir1.path()); 105 ASSERT_THAT(rename(f.path().c_str(), newpath.c_str()), SyscallSucceeds()); 106 std::string const oldpath = f.release(); 107 f.reset(newpath); 108 EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false)); 109 EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true)); 110 } 111 112 TEST(RenameTest, DirectoryToParentDirectory) { 113 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 114 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 115 auto dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir2.path())); 116 EXPECT_THAT(IsDirectory(dir3.path()), IsPosixErrorOkAndHolds(true)); 117 std::string const newpath = NewTempAbsPathInDir(dir1.path()); 118 ASSERT_THAT(rename(dir3.path().c_str(), newpath.c_str()), SyscallSucceeds()); 119 std::string const oldpath = dir3.release(); 120 dir3.reset(newpath); 121 EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false)); 122 EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true)); 123 EXPECT_THAT(IsDirectory(newpath), IsPosixErrorOkAndHolds(true)); 124 } 125 126 TEST(RenameTest, FileToChildDirectory) { 127 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 128 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 129 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 130 std::string const newpath = NewTempAbsPathInDir(dir2.path()); 131 ASSERT_THAT(rename(f.path().c_str(), newpath.c_str()), SyscallSucceeds()); 132 std::string const oldpath = f.release(); 133 f.reset(newpath); 134 EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false)); 135 EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true)); 136 } 137 138 TEST(RenameTest, DirectoryToChildDirectory) { 139 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 140 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 141 auto dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 142 std::string const newpath = NewTempAbsPathInDir(dir2.path()); 143 ASSERT_THAT(rename(dir3.path().c_str(), newpath.c_str()), SyscallSucceeds()); 144 std::string const oldpath = dir3.release(); 145 dir3.reset(newpath); 146 EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false)); 147 EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true)); 148 EXPECT_THAT(IsDirectory(newpath), IsPosixErrorOkAndHolds(true)); 149 } 150 151 TEST(RenameTest, DirectoryToOwnChildDirectory) { 152 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 153 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path())); 154 std::string const newpath = NewTempAbsPathInDir(dir2.path()); 155 ASSERT_THAT(rename(dir1.path().c_str(), newpath.c_str()), 156 SyscallFailsWithErrno(EINVAL)); 157 } 158 159 TEST(RenameTest, FileOverwritesFile) { 160 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 161 auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 162 dir.path(), "first", TempPath::kDefaultFileMode)); 163 auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 164 dir.path(), "second", TempPath::kDefaultFileMode)); 165 ASSERT_THAT(rename(f1.path().c_str(), f2.path().c_str()), SyscallSucceeds()); 166 EXPECT_THAT(Exists(f1.path()), IsPosixErrorOkAndHolds(false)); 167 168 f1.release(); 169 std::string f2_contents; 170 ASSERT_NO_ERRNO(GetContents(f2.path(), &f2_contents)); 171 EXPECT_EQ("first", f2_contents); 172 } 173 174 TEST(RenameTest, DirectoryOverwritesDirectoryLinkCount) { 175 // Directory link counts are synthetic on overlay filesystems. 176 SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(GetAbsoluteTestTmpdir()))); 177 178 auto parent1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 179 EXPECT_THAT(Links(parent1.path()), IsPosixErrorOkAndHolds(2)); 180 181 auto parent2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 182 EXPECT_THAT(Links(parent2.path()), IsPosixErrorOkAndHolds(2)); 183 184 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent1.path())); 185 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent2.path())); 186 187 EXPECT_THAT(Links(parent1.path()), IsPosixErrorOkAndHolds(3)); 188 EXPECT_THAT(Links(parent2.path()), IsPosixErrorOkAndHolds(3)); 189 190 ASSERT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()), 191 SyscallSucceeds()); 192 193 EXPECT_THAT(Links(parent1.path()), IsPosixErrorOkAndHolds(2)); 194 EXPECT_THAT(Links(parent2.path()), IsPosixErrorOkAndHolds(3)); 195 } 196 197 TEST(RenameTest, FileDoesNotExist) { 198 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 199 const std::string source = JoinPath(dir.path(), "source"); 200 const std::string dest = JoinPath(dir.path(), "dest"); 201 ASSERT_THAT(rename(source.c_str(), dest.c_str()), 202 SyscallFailsWithErrno(ENOENT)); 203 } 204 205 TEST(RenameTest, FileDoesNotOverwriteDirectory) { 206 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 207 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 208 ASSERT_THAT(rename(f.path().c_str(), dir.path().c_str()), 209 SyscallFailsWithErrno(EISDIR)); 210 } 211 212 TEST(RenameTest, DirectoryDoesNotOverwriteFile) { 213 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 214 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 215 ASSERT_THAT(rename(dir.path().c_str(), f.path().c_str()), 216 SyscallFailsWithErrno(ENOTDIR)); 217 } 218 219 TEST(RenameTest, DirectoryOverwritesEmptyDirectory) { 220 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 221 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 222 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 223 EXPECT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()), 224 SyscallSucceeds()); 225 EXPECT_THAT(Exists(dir1.path()), IsPosixErrorOkAndHolds(false)); 226 dir1.release(); 227 EXPECT_THAT(Exists(JoinPath(dir2.path(), Basename(f.path()))), 228 IsPosixErrorOkAndHolds(true)); 229 f.release(); 230 } 231 232 TEST(RenameTest, FailsWithDots) { 233 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 234 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 235 auto dir1_dot = absl::StrCat(dir1.path(), "/."); 236 auto dir2_dot = absl::StrCat(dir2.path(), "/."); 237 auto dir1_dot_dot = absl::StrCat(dir1.path(), "/.."); 238 auto dir2_dot_dot = absl::StrCat(dir2.path(), "/.."); 239 240 // Try with dot paths in the first argument 241 EXPECT_THAT(rename(dir1_dot.c_str(), dir2.path().c_str()), 242 SyscallFailsWithErrno(EBUSY)); 243 EXPECT_THAT(rename(dir1_dot_dot.c_str(), dir2.path().c_str()), 244 SyscallFailsWithErrno(EBUSY)); 245 246 // Try with dot paths in the second argument 247 EXPECT_THAT(rename(dir1.path().c_str(), dir2_dot.c_str()), 248 SyscallFailsWithErrno(EBUSY)); 249 EXPECT_THAT(rename(dir1.path().c_str(), dir2_dot_dot.c_str()), 250 SyscallFailsWithErrno(EBUSY)); 251 } 252 253 TEST(RenameTest, DirectoryDoesNotOverwriteNonemptyDirectory) { 254 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 255 auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 256 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 257 auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir2.path())); 258 ASSERT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()), 259 SyscallFailsWithErrno(ENOTEMPTY)); 260 } 261 262 TEST(RenameTest, FailsWhenOldParentNotWritable) { 263 // Drop capabilities that allow us to override file and directory permissions. 264 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 265 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 266 267 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 268 auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 269 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 270 // dir1 is not writable. 271 ASSERT_THAT(chmod(dir1.path().c_str(), 0555), SyscallSucceeds()); 272 273 std::string const newpath = NewTempAbsPathInDir(dir2.path()); 274 EXPECT_THAT(rename(f1.path().c_str(), newpath.c_str()), 275 SyscallFailsWithErrno(EACCES)); 276 } 277 278 TEST(RenameTest, FailsWhenNewParentNotWritable) { 279 // Drop capabilities that allow us to override file and directory permissions. 280 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 281 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 282 283 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 284 auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 285 // dir2 is not writable. 286 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE( 287 TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0555)); 288 289 std::string const newpath = NewTempAbsPathInDir(dir2.path()); 290 EXPECT_THAT(rename(f1.path().c_str(), newpath.c_str()), 291 SyscallFailsWithErrno(EACCES)); 292 } 293 294 // Equivalent to FailsWhenNewParentNotWritable, but with a destination file 295 // to overwrite. 296 TEST(RenameTest, OverwriteFailsWhenNewParentNotWritable) { 297 // Drop capabilities that allow us to override file and directory permissions. 298 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 299 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 300 301 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 302 auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 303 304 // dir2 is not writable. 305 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 306 auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir2.path())); 307 ASSERT_THAT(chmod(dir2.path().c_str(), 0555), SyscallSucceeds()); 308 309 EXPECT_THAT(rename(f1.path().c_str(), f2.path().c_str()), 310 SyscallFailsWithErrno(EACCES)); 311 } 312 313 // If the parent directory of source is not accessible, rename returns EACCES 314 // because the user cannot determine if source exists. 315 TEST(RenameTest, FileDoesNotExistWhenNewParentNotExecutable) { 316 // Drop capabilities that allow us to override file and directory permissions. 317 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 318 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 319 320 // No execute permission. 321 auto dir = ASSERT_NO_ERRNO_AND_VALUE( 322 TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0400)); 323 324 const std::string source = JoinPath(dir.path(), "source"); 325 const std::string dest = JoinPath(dir.path(), "dest"); 326 ASSERT_THAT(rename(source.c_str(), dest.c_str()), 327 SyscallFailsWithErrno(EACCES)); 328 } 329 330 TEST(RenameTest, DirectoryWithOpenFdOverwritesEmptyDirectory) { 331 auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 332 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path())); 333 auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 334 335 // Get an fd on dir1 336 int fd; 337 ASSERT_THAT(fd = open(dir1.path().c_str(), O_DIRECTORY), SyscallSucceeds()); 338 auto close_f = Cleanup([fd] { 339 // Close the fd on f. 340 EXPECT_THAT(close(fd), SyscallSucceeds()); 341 }); 342 343 EXPECT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()), 344 SyscallSucceeds()); 345 346 const std::string new_f_path = JoinPath(dir2.path(), Basename(f.path())); 347 348 auto remove_f = Cleanup([&] { 349 // Delete f in its new location. 350 ASSERT_NO_ERRNO(Delete(new_f_path)); 351 f.release(); 352 }); 353 354 EXPECT_THAT(Exists(dir1.path()), IsPosixErrorOkAndHolds(false)); 355 dir1.release(); 356 EXPECT_THAT(Exists(new_f_path), IsPosixErrorOkAndHolds(true)); 357 } 358 359 TEST(RenameTest, FileWithOpenFd) { 360 TempPath root_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 361 TempPath dir1 = 362 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); 363 TempPath dir2 = 364 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); 365 TempPath dir3 = 366 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); 367 368 // Create file in dir1. 369 constexpr char kContents[] = "foo"; 370 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith( 371 dir1.path(), kContents, TempPath::kDefaultFileMode)); 372 373 // Get fd on file. 374 const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDWR)); 375 376 // Move f to dir2. 377 const std::string path2 = NewTempAbsPathInDir(dir2.path()); 378 ASSERT_THAT(rename(f.path().c_str(), path2.c_str()), SyscallSucceeds()); 379 380 // Read f's kContents. 381 char buf[sizeof(kContents)]; 382 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(kContents), 0), 383 SyscallSucceedsWithValue(sizeof(kContents) - 1)); 384 EXPECT_EQ(absl::string_view(buf, sizeof(buf) - 1), kContents); 385 386 // Move f to dir3. 387 const std::string path3 = NewTempAbsPathInDir(dir3.path()); 388 ASSERT_THAT(rename(path2.c_str(), path3.c_str()), SyscallSucceeds()); 389 390 // Read f's kContents. 391 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(kContents), 0), 392 SyscallSucceedsWithValue(sizeof(kContents) - 1)); 393 EXPECT_EQ(absl::string_view(buf, sizeof(buf) - 1), kContents); 394 } 395 396 // Tests that calling rename with file path ending with . or .. causes EBUSY. 397 TEST(RenameTest, PathEndingWithDots) { 398 TempPath root_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 399 TempPath dir1 = 400 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); 401 TempPath dir2 = 402 ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path())); 403 404 // Try to move dir1 into dir2 but mess up the paths. 405 auto dir1Dot = JoinPath(dir1.path(), "."); 406 auto dir2Dot = JoinPath(dir2.path(), "."); 407 auto dir1DotDot = JoinPath(dir1.path(), ".."); 408 auto dir2DotDot = JoinPath(dir2.path(), ".."); 409 ASSERT_THAT(rename(dir1.path().c_str(), dir2Dot.c_str()), 410 SyscallFailsWithErrno(EBUSY)); 411 ASSERT_THAT(rename(dir1.path().c_str(), dir2DotDot.c_str()), 412 SyscallFailsWithErrno(EBUSY)); 413 ASSERT_THAT(rename(dir1Dot.c_str(), dir2.path().c_str()), 414 SyscallFailsWithErrno(EBUSY)); 415 ASSERT_THAT(rename(dir1DotDot.c_str(), dir2.path().c_str()), 416 SyscallFailsWithErrno(EBUSY)); 417 } 418 419 // Calling rename with file path ending with . or .. causes EBUSY in sysfs. 420 TEST(RenameTest, SysfsPathEndingWithDots) { 421 // If a non-root user tries to rename inside /sys then we get EPERM. 422 SKIP_IF(geteuid() != 0); 423 ASSERT_THAT(rename("/sys/devices/system/cpu/online", "/sys/."), 424 SyscallFailsWithErrno(EBUSY)); 425 ASSERT_THAT(rename("/sys/devices/system/cpu/online", "/sys/.."), 426 SyscallFailsWithErrno(EBUSY)); 427 } 428 429 TEST(RenameTest, SysfsFileToSelf) { 430 // If a non-root user tries to rename inside /sys then we get EPERM. 431 SKIP_IF(geteuid() != 0); 432 std::string const path = "/sys/devices/system/cpu/online"; 433 EXPECT_THAT(rename(path.c_str(), path.c_str()), SyscallSucceeds()); 434 } 435 436 TEST(RenameTest, SysfsDirectoryToSelf) { 437 // If a non-root user tries to rename inside /sys then we get EPERM. 438 SKIP_IF(geteuid() != 0); 439 std::string const path = "/sys/devices"; 440 EXPECT_THAT(rename(path.c_str(), path.c_str()), SyscallSucceeds()); 441 } 442 443 #ifndef SYS_renameat2 444 #if defined(__x86_64__) 445 #define SYS_renameat2 316 446 #elif defined(__aarch64__) 447 #define SYS_renameat2 276 448 #else 449 #error "Unknown architecture" 450 #endif 451 #endif // SYS_renameat2 452 453 #ifndef RENAME_NOREPLACE 454 #define RENAME_NOREPLACE (1 << 0) 455 #endif // RENAME_NOREPLACE 456 457 int renameat2(int olddirfd, const char* oldpath, int newdirfd, 458 const char* newpath, unsigned int flags) { 459 return syscall(SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags); 460 } 461 462 TEST(Renameat2Test, NoReplaceSuccess) { 463 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 464 std::string const newpath = NewTempAbsPath(); 465 // renameat2 may fail with ENOSYS (if the syscall is unsupported) or EINVAL 466 // (if flags are unsupported), or succeed (if RENAME_NOREPLACE is operating 467 // correctly). 468 EXPECT_THAT( 469 renameat2(AT_FDCWD, f.path().c_str(), AT_FDCWD, newpath.c_str(), 470 RENAME_NOREPLACE), 471 AnyOf(SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL)), SyscallSucceeds())); 472 } 473 474 TEST(Renameat2Test, NoReplaceExisting) { 475 auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 476 auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 477 // renameat2 may fail with ENOSYS (if the syscall is unsupported), EINVAL (if 478 // flags are unsupported), or EEXIST (if RENAME_NOREPLACE is operating 479 // correctly). 480 EXPECT_THAT(renameat2(AT_FDCWD, f1.path().c_str(), AT_FDCWD, 481 f2.path().c_str(), RENAME_NOREPLACE), 482 SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL, EEXIST))); 483 } 484 485 TEST(Renameat2Test, NoReplaceDot) { 486 auto d1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 487 auto d2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 488 // renameat2 may fail with ENOSYS (if the syscall is unsupported), EINVAL (if 489 // flags are unsupported), or EEXIST (if RENAME_NOREPLACE is operating 490 // correctly). 491 EXPECT_THAT( 492 renameat2(AT_FDCWD, d1.path().c_str(), AT_FDCWD, 493 absl::StrCat(d2.path(), "/.").c_str(), RENAME_NOREPLACE), 494 SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL, EEXIST))); 495 } 496 497 } // namespace 498 499 } // namespace testing 500 } // namespace gvisor