github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/symlink.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 <string.h> 18 #include <unistd.h> 19 20 #include <string> 21 22 #include "gtest/gtest.h" 23 #include "absl/time/clock.h" 24 #include "test/util/capability_util.h" 25 #include "test/util/file_descriptor.h" 26 #include "test/util/fs_util.h" 27 #include "test/util/temp_path.h" 28 #include "test/util/test_util.h" 29 30 namespace gvisor { 31 namespace testing { 32 33 namespace { 34 35 mode_t FilePermission(const std::string& path) { 36 struct stat buf = {0}; 37 TEST_CHECK(lstat(path.c_str(), &buf) == 0); 38 return buf.st_mode & 0777; 39 } 40 41 // Test that name collisions are checked on the new link path, not the source 42 // path. Regression test for b/31782115. 43 TEST(SymlinkTest, CanCreateSymlinkWithCachedSourceDirent) { 44 const std::string srcname = NewTempAbsPath(); 45 const std::string newname = NewTempAbsPath(); 46 const std::string basedir = std::string(Dirname(srcname)); 47 ASSERT_EQ(basedir, Dirname(newname)); 48 49 ASSERT_THAT(chdir(basedir.c_str()), SyscallSucceeds()); 50 51 // Open the source node to cause the underlying dirent to be cached. It will 52 // remain cached while we have the file open. 53 int fd; 54 ASSERT_THAT(fd = open(srcname.c_str(), O_CREAT | O_RDWR, 0666), 55 SyscallSucceeds()); 56 FileDescriptor fd_closer(fd); 57 58 // Attempt to create a symlink. If the bug exists, this will fail since the 59 // dirent link creation code will check for a name collision on the source 60 // link name. 61 EXPECT_THAT(symlink(std::string(Basename(srcname)).c_str(), 62 std::string(Basename(newname)).c_str()), 63 SyscallSucceeds()); 64 } 65 66 TEST(SymlinkTest, CanCreateSymlinkFile) { 67 const std::string oldname = NewTempAbsPath(); 68 const std::string newname = NewTempAbsPath(); 69 70 int fd; 71 ASSERT_THAT(fd = open(oldname.c_str(), O_CREAT | O_RDWR, 0666), 72 SyscallSucceeds()); 73 EXPECT_THAT(close(fd), SyscallSucceeds()); 74 75 EXPECT_THAT(symlink(oldname.c_str(), newname.c_str()), SyscallSucceeds()); 76 EXPECT_EQ(FilePermission(newname), 0777); 77 78 auto link = ASSERT_NO_ERRNO_AND_VALUE(ReadLink(newname)); 79 EXPECT_EQ(oldname, link); 80 81 EXPECT_THAT(unlink(newname.c_str()), SyscallSucceeds()); 82 EXPECT_THAT(unlink(oldname.c_str()), SyscallSucceeds()); 83 } 84 85 TEST(SymlinkTest, CanCreateSymlinkDir) { 86 const std::string olddir = NewTempAbsPath(); 87 const std::string newdir = NewTempAbsPath(); 88 89 EXPECT_THAT(mkdir(olddir.c_str(), 0777), SyscallSucceeds()); 90 EXPECT_THAT(symlink(olddir.c_str(), newdir.c_str()), SyscallSucceeds()); 91 EXPECT_EQ(FilePermission(newdir), 0777); 92 93 auto link = ASSERT_NO_ERRNO_AND_VALUE(ReadLink(newdir)); 94 EXPECT_EQ(olddir, link); 95 96 EXPECT_THAT(unlink(newdir.c_str()), SyscallSucceeds()); 97 98 ASSERT_THAT(rmdir(olddir.c_str()), SyscallSucceeds()); 99 } 100 101 TEST(SymlinkTest, CannotCreateSymlinkInReadOnlyDir) { 102 // Drop capabilities that allow us to override file and directory permissions. 103 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 104 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 105 106 const std::string olddir = NewTempAbsPath(); 107 ASSERT_THAT(mkdir(olddir.c_str(), 0444), SyscallSucceeds()); 108 109 const std::string newdir = NewTempAbsPathInDir(olddir); 110 EXPECT_THAT(symlink(olddir.c_str(), newdir.c_str()), 111 SyscallFailsWithErrno(EACCES)); 112 113 ASSERT_THAT(rmdir(olddir.c_str()), SyscallSucceeds()); 114 } 115 116 TEST(SymlinkTest, CannotSymlinkOverExistingFile) { 117 const auto oldfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 118 const auto newfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 119 120 EXPECT_THAT(symlink(oldfile.path().c_str(), newfile.path().c_str()), 121 SyscallFailsWithErrno(EEXIST)); 122 } 123 124 TEST(SymlinkTest, CannotSymlinkOverExistingDir) { 125 const auto oldfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 126 const auto newdir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 127 128 EXPECT_THAT(symlink(oldfile.path().c_str(), newdir.path().c_str()), 129 SyscallFailsWithErrno(EEXIST)); 130 } 131 132 TEST(SymlinkTest, OldnameIsEmpty) { 133 const std::string newname = NewTempAbsPath(); 134 EXPECT_THAT(symlink("", newname.c_str()), SyscallFailsWithErrno(ENOENT)); 135 } 136 137 TEST(SymlinkTest, OldnameIsDangling) { 138 const std::string newname = NewTempAbsPath(); 139 EXPECT_THAT(symlink("/dangling", newname.c_str()), SyscallSucceeds()); 140 141 // This is required for S/R random save tests, which pre-run this test 142 // in the same TEST_TMPDIR, which means that we need to clean it for any 143 // operations exclusively creating files, like symlink above. 144 EXPECT_THAT(unlink(newname.c_str()), SyscallSucceeds()); 145 } 146 147 TEST(SymlinkTest, NewnameCannotExist) { 148 const std::string newname = 149 JoinPath(GetAbsoluteTestTmpdir(), "thisdoesnotexist", "foo"); 150 EXPECT_THAT(symlink("/thisdoesnotmatter", newname.c_str()), 151 SyscallFailsWithErrno(ENOENT)); 152 } 153 154 TEST(SymlinkTest, CanEvaluateLink) { 155 const auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 156 157 // We are going to assert that the symlink inode id is the same as the linked 158 // file's inode id. In order for the inode id to be stable across 159 // save/restore, it must be kept open. The FileDescriptor type will do that 160 // for us automatically. 161 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR)); 162 struct stat file_st; 163 EXPECT_THAT(fstat(fd.get(), &file_st), SyscallSucceeds()); 164 165 const std::string link = NewTempAbsPath(); 166 EXPECT_THAT(symlink(file.path().c_str(), link.c_str()), SyscallSucceeds()); 167 EXPECT_EQ(FilePermission(link), 0777); 168 169 auto linkfd = ASSERT_NO_ERRNO_AND_VALUE(Open(link.c_str(), O_RDWR)); 170 struct stat link_st; 171 EXPECT_THAT(fstat(linkfd.get(), &link_st), SyscallSucceeds()); 172 173 // Check that in fact newname points to the file we expect. 174 EXPECT_EQ(file_st.st_dev, link_st.st_dev); 175 EXPECT_EQ(file_st.st_ino, link_st.st_ino); 176 } 177 178 TEST(SymlinkTest, TargetIsNotMapped) { 179 const std::string oldname = NewTempAbsPath(); 180 const std::string newname = NewTempAbsPath(); 181 182 int fd; 183 // Create the target so that when we read the link, it exists. 184 ASSERT_THAT(fd = open(oldname.c_str(), O_CREAT | O_RDWR, 0666), 185 SyscallSucceeds()); 186 EXPECT_THAT(close(fd), SyscallSucceeds()); 187 188 // Create a symlink called newname that points to oldname. 189 EXPECT_THAT(symlink(oldname.c_str(), newname.c_str()), SyscallSucceeds()); 190 191 std::vector<char> buf(1024); 192 int linksize; 193 // Read the link and assert that the oldname is still the same. 194 EXPECT_THAT(linksize = readlink(newname.c_str(), buf.data(), 1024), 195 SyscallSucceeds()); 196 EXPECT_EQ(0, strncmp(oldname.c_str(), buf.data(), linksize)); 197 198 EXPECT_THAT(unlink(newname.c_str()), SyscallSucceeds()); 199 EXPECT_THAT(unlink(oldname.c_str()), SyscallSucceeds()); 200 } 201 202 TEST(SymlinkTest, PreadFromSymlink) { 203 std::string name = NewTempAbsPath(); 204 int fd; 205 ASSERT_THAT(fd = open(name.c_str(), O_CREAT, 0644), SyscallSucceeds()); 206 ASSERT_THAT(close(fd), SyscallSucceeds()); 207 208 std::string linkname = NewTempAbsPath(); 209 ASSERT_THAT(symlink(name.c_str(), linkname.c_str()), SyscallSucceeds()); 210 211 ASSERT_THAT(fd = open(linkname.c_str(), O_RDONLY), SyscallSucceeds()); 212 213 char buf[1024]; 214 EXPECT_THAT(pread64(fd, buf, 1024, 0), SyscallSucceeds()); 215 EXPECT_THAT(close(fd), SyscallSucceeds()); 216 217 EXPECT_THAT(unlink(name.c_str()), SyscallSucceeds()); 218 EXPECT_THAT(unlink(linkname.c_str()), SyscallSucceeds()); 219 } 220 221 TEST(SymlinkTest, PwriteToSymlink) { 222 std::string name = NewTempAbsPath(); 223 int fd; 224 ASSERT_THAT(fd = open(name.c_str(), O_CREAT, 0644), SyscallSucceeds()); 225 ASSERT_THAT(close(fd), SyscallSucceeds()); 226 227 std::string linkname = NewTempAbsPath(); 228 ASSERT_THAT(symlink(name.c_str(), linkname.c_str()), SyscallSucceeds()); 229 230 ASSERT_THAT(fd = open(linkname.c_str(), O_WRONLY), SyscallSucceeds()); 231 232 const int data_size = 10; 233 const std::string data = std::string(data_size, 'a'); 234 EXPECT_THAT(pwrite64(fd, data.c_str(), data.size(), 0), 235 SyscallSucceedsWithValue(data.size())); 236 237 ASSERT_THAT(close(fd), SyscallSucceeds()); 238 ASSERT_THAT(fd = open(name.c_str(), O_RDONLY), SyscallSucceeds()); 239 240 char buf[data_size + 1]; 241 EXPECT_THAT(pread64(fd, buf, data.size(), 0), SyscallSucceeds()); 242 buf[data.size()] = '\0'; 243 EXPECT_STREQ(buf, data.c_str()); 244 245 ASSERT_THAT(close(fd), SyscallSucceeds()); 246 247 EXPECT_THAT(unlink(name.c_str()), SyscallSucceeds()); 248 EXPECT_THAT(unlink(linkname.c_str()), SyscallSucceeds()); 249 } 250 251 TEST(SymlinkTest, SymlinkAtDegradedPermissions) { 252 // Drop capabilities that allow us to override file and directory permissions. 253 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 254 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 255 256 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 257 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path())); 258 259 int dirfd; 260 ASSERT_THAT(dirfd = open(dir.path().c_str(), O_DIRECTORY, 0), 261 SyscallSucceeds()); 262 263 const DisableSave ds; // Permissions are dropped. 264 EXPECT_THAT(fchmod(dirfd, 0), SyscallSucceeds()); 265 266 std::string basename = std::string(Basename(file.path())); 267 EXPECT_THAT(symlinkat("/dangling", dirfd, basename.c_str()), 268 SyscallFailsWithErrno(EACCES)); 269 EXPECT_THAT(close(dirfd), SyscallSucceeds()); 270 } 271 272 TEST(SymlinkTest, SymlinkAtDirWithOpath) { 273 SKIP_IF(IsRunningWithVFS1()); 274 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 275 const std::string filepath = NewTempAbsPathInDir(dir.path()); 276 const std::string base = std::string(Basename(filepath)); 277 FileDescriptor dirfd = 278 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path().c_str(), O_DIRECTORY | O_PATH)); 279 280 EXPECT_THAT(symlinkat("/dangling", dirfd.get(), base.c_str()), 281 SyscallSucceeds()); 282 } 283 284 TEST(SymlinkTest, ReadlinkAtDirWithOpath) { 285 SKIP_IF(IsRunningWithVFS1()); 286 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 287 const std::string filepath = NewTempAbsPathInDir(dir.path()); 288 const std::string base = std::string(Basename(filepath)); 289 ASSERT_THAT(symlink("/dangling", filepath.c_str()), SyscallSucceeds()); 290 291 FileDescriptor dirfd = 292 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path().c_str(), O_DIRECTORY | O_PATH)); 293 294 std::vector<char> buf(1024); 295 int linksize; 296 EXPECT_THAT( 297 linksize = readlinkat(dirfd.get(), base.c_str(), buf.data(), 1024), 298 SyscallSucceeds()); 299 EXPECT_EQ(0, strncmp("/dangling", buf.data(), linksize)); 300 } 301 302 TEST(SymlinkTest, ReadlinkAtDegradedPermissions) { 303 // Drop capabilities that allow us to override file and directory permissions. 304 AutoCapability cap1(CAP_DAC_OVERRIDE, false); 305 AutoCapability cap2(CAP_DAC_READ_SEARCH, false); 306 307 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 308 const std::string oldpath = NewTempAbsPathInDir(dir.path()); 309 const std::string oldbase = std::string(Basename(oldpath)); 310 ASSERT_THAT(symlink("/dangling", oldpath.c_str()), SyscallSucceeds()); 311 312 int dirfd; 313 EXPECT_THAT(dirfd = open(dir.path().c_str(), O_DIRECTORY, 0), 314 SyscallSucceeds()); 315 316 const DisableSave ds; // Permissions are dropped. 317 EXPECT_THAT(fchmod(dirfd, 0), SyscallSucceeds()); 318 319 char buf[1024]; 320 int linksize; 321 EXPECT_THAT(linksize = readlinkat(dirfd, oldbase.c_str(), buf, 1024), 322 SyscallFailsWithErrno(EACCES)); 323 EXPECT_THAT(close(dirfd), SyscallSucceeds()); 324 } 325 326 TEST(SymlinkTest, ChmodSymlink) { 327 auto target = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 328 const std::string newpath = NewTempAbsPath(); 329 ASSERT_THAT(symlink(target.path().c_str(), newpath.c_str()), 330 SyscallSucceeds()); 331 EXPECT_EQ(FilePermission(newpath), 0777); 332 EXPECT_THAT(chmod(newpath.c_str(), 0666), SyscallSucceeds()); 333 EXPECT_EQ(FilePermission(newpath), 0777); 334 } 335 336 // Test that following a symlink updates the atime on the symlink. 337 TEST(SymlinkTest, FollowUpdatesATime) { 338 const auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 339 const std::string link = NewTempAbsPath(); 340 EXPECT_THAT(symlink(file.path().c_str(), link.c_str()), SyscallSucceeds()); 341 342 // Lstat the symlink. 343 struct stat st_before_follow; 344 ASSERT_THAT(lstat(link.c_str(), &st_before_follow), SyscallSucceeds()); 345 346 // Let the clock advance. 347 absl::SleepFor(absl::Seconds(1)); 348 349 // Open the file via the symlink. 350 int fd; 351 ASSERT_THAT(fd = open(link.c_str(), O_RDWR, 0666), SyscallSucceeds()); 352 FileDescriptor fd_closer(fd); 353 354 // Lstat the symlink again, and check that atime is updated. 355 struct stat st_after_follow; 356 ASSERT_THAT(lstat(link.c_str(), &st_after_follow), SyscallSucceeds()); 357 EXPECT_LT(st_before_follow.st_atime, st_after_follow.st_atime); 358 } 359 360 TEST(SymlinkTest, SymlinkAtEmptyPath) { 361 auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 362 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 363 364 auto fd = 365 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY | O_DIRECTORY, 0666)); 366 EXPECT_THAT(symlinkat(file.path().c_str(), fd.get(), ""), 367 SyscallFailsWithErrno(ENOENT)); 368 } 369 370 class ParamSymlinkTest : public ::testing::TestWithParam<std::string> {}; 371 372 // Test that creating an existing symlink with creat will create the target. 373 TEST_P(ParamSymlinkTest, CreatLinkCreatesTarget) { 374 const std::string target = GetParam(); 375 const std::string linkpath = NewTempAbsPath(); 376 377 ASSERT_THAT(symlink(target.c_str(), linkpath.c_str()), SyscallSucceeds()); 378 379 int fd; 380 EXPECT_THAT(fd = creat(linkpath.c_str(), 0666), SyscallSucceeds()); 381 ASSERT_THAT(close(fd), SyscallSucceeds()); 382 383 ASSERT_THAT(chdir(GetAbsoluteTestTmpdir().c_str()), SyscallSucceeds()); 384 struct stat st; 385 EXPECT_THAT(stat(target.c_str(), &st), SyscallSucceeds()); 386 387 ASSERT_THAT(unlink(linkpath.c_str()), SyscallSucceeds()); 388 ASSERT_THAT(unlink(target.c_str()), SyscallSucceeds()); 389 } 390 391 // Test that opening an existing symlink with O_CREAT will create the target. 392 TEST_P(ParamSymlinkTest, OpenLinkCreatesTarget) { 393 const std::string target = GetParam(); 394 const std::string linkpath = NewTempAbsPath(); 395 396 ASSERT_THAT(symlink(target.c_str(), linkpath.c_str()), SyscallSucceeds()); 397 398 int fd; 399 EXPECT_THAT(fd = open(linkpath.c_str(), O_CREAT, 0666), SyscallSucceeds()); 400 ASSERT_THAT(close(fd), SyscallSucceeds()); 401 402 ASSERT_THAT(chdir(GetAbsoluteTestTmpdir().c_str()), SyscallSucceeds()); 403 struct stat st; 404 EXPECT_THAT(stat(target.c_str(), &st), SyscallSucceeds()); 405 406 ASSERT_THAT(unlink(linkpath.c_str()), SyscallSucceeds()); 407 ASSERT_THAT(unlink(target.c_str()), SyscallSucceeds()); 408 } 409 410 // Test that opening a self-symlink with O_CREAT will fail with ELOOP. 411 TEST_P(ParamSymlinkTest, CreateExistingSelfLink) { 412 ASSERT_THAT(chdir(GetAbsoluteTestTmpdir().c_str()), SyscallSucceeds()); 413 414 const std::string linkpath = GetParam(); 415 ASSERT_THAT(symlink(linkpath.c_str(), linkpath.c_str()), SyscallSucceeds()); 416 417 EXPECT_THAT(open(linkpath.c_str(), O_CREAT, 0666), 418 SyscallFailsWithErrno(ELOOP)); 419 420 ASSERT_THAT(unlink(linkpath.c_str()), SyscallSucceeds()); 421 } 422 423 // Test that opening a file that is a symlink to its parent directory fails 424 // with ELOOP. 425 TEST_P(ParamSymlinkTest, CreateExistingParentLink) { 426 ASSERT_THAT(chdir(GetAbsoluteTestTmpdir().c_str()), SyscallSucceeds()); 427 428 const std::string linkpath = GetParam(); 429 const std::string target = JoinPath(linkpath, "child"); 430 ASSERT_THAT(symlink(target.c_str(), linkpath.c_str()), SyscallSucceeds()); 431 432 EXPECT_THAT(open(linkpath.c_str(), O_CREAT, 0666), 433 SyscallFailsWithErrno(ELOOP)); 434 435 ASSERT_THAT(unlink(linkpath.c_str()), SyscallSucceeds()); 436 } 437 438 // Test that opening an existing symlink with O_CREAT|O_EXCL will fail with 439 // EEXIST. 440 TEST_P(ParamSymlinkTest, OpenLinkExclFails) { 441 const std::string target = GetParam(); 442 const std::string linkpath = NewTempAbsPath(); 443 444 ASSERT_THAT(symlink(target.c_str(), linkpath.c_str()), SyscallSucceeds()); 445 446 EXPECT_THAT(open(linkpath.c_str(), O_CREAT | O_EXCL, 0666), 447 SyscallFailsWithErrno(EEXIST)); 448 449 ASSERT_THAT(unlink(linkpath.c_str()), SyscallSucceeds()); 450 } 451 452 // Test that opening an existing symlink with O_CREAT|O_NOFOLLOW will fail with 453 // ELOOP. 454 TEST_P(ParamSymlinkTest, OpenLinkNoFollowFails) { 455 const std::string target = GetParam(); 456 const std::string linkpath = NewTempAbsPath(); 457 458 ASSERT_THAT(symlink(target.c_str(), linkpath.c_str()), SyscallSucceeds()); 459 460 EXPECT_THAT(open(linkpath.c_str(), O_CREAT | O_NOFOLLOW, 0666), 461 SyscallFailsWithErrno(ELOOP)); 462 463 ASSERT_THAT(unlink(linkpath.c_str()), SyscallSucceeds()); 464 } 465 466 INSTANTIATE_TEST_SUITE_P(AbsAndRelTarget, ParamSymlinkTest, 467 ::testing::Values(NewTempAbsPath(), NewTempRelPath())); 468 469 } // namespace 470 471 } // namespace testing 472 } // namespace gvisor