github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/unlink.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 <unistd.h>
    18  
    19  #include "gtest/gtest.h"
    20  #include "absl/strings/str_cat.h"
    21  #include "test/util/capability_util.h"
    22  #include "test/util/file_descriptor.h"
    23  #include "test/util/fs_util.h"
    24  #include "test/util/temp_path.h"
    25  #include "test/util/test_util.h"
    26  
    27  namespace gvisor {
    28  namespace testing {
    29  
    30  namespace {
    31  
    32  TEST(UnlinkTest, IsDir) {
    33    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    34  
    35    EXPECT_THAT(unlink(dir.path().c_str()), SyscallFailsWithErrno(EISDIR));
    36  }
    37  
    38  TEST(UnlinkTest, DirNotEmpty) {
    39    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    40  
    41    int fd;
    42    std::string path = JoinPath(dir.path(), "ExistingFile");
    43    EXPECT_THAT(fd = open(path.c_str(), O_RDWR | O_CREAT, 0666),
    44                SyscallSucceeds());
    45    EXPECT_THAT(close(fd), SyscallSucceeds());
    46    EXPECT_THAT(rmdir(dir.path().c_str()), SyscallFailsWithErrno(ENOTEMPTY));
    47  }
    48  
    49  TEST(UnlinkTest, Rmdir) {
    50    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    51    EXPECT_THAT(rmdir(dir.path().c_str()), SyscallSucceeds());
    52  }
    53  
    54  TEST(UnlinkTest, AtDir) {
    55    int dirfd;
    56    auto tmpdir = GetAbsoluteTestTmpdir();
    57    EXPECT_THAT(dirfd = open(tmpdir.c_str(), O_DIRECTORY, 0), SyscallSucceeds());
    58  
    59    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(tmpdir));
    60    auto dir_relpath =
    61        ASSERT_NO_ERRNO_AND_VALUE(GetRelativePath(tmpdir, dir.path()));
    62    EXPECT_THAT(unlinkat(dirfd, dir_relpath.c_str(), AT_REMOVEDIR),
    63                SyscallSucceeds());
    64    ASSERT_THAT(close(dirfd), SyscallSucceeds());
    65  }
    66  
    67  TEST(UnlinkTest, AtDirDegradedPermissions) {
    68    // Drop capabilities that allow us to override file and directory permissions.
    69    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
    70    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
    71  
    72    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    73  
    74    int dirfd;
    75    ASSERT_THAT(dirfd = open(dir.path().c_str(), O_DIRECTORY, 0),
    76                SyscallSucceeds());
    77  
    78    std::string sub_dir = JoinPath(dir.path(), "NewDir");
    79    EXPECT_THAT(mkdir(sub_dir.c_str(), 0755), SyscallSucceeds());
    80    EXPECT_THAT(fchmod(dirfd, 0444), SyscallSucceeds());
    81    EXPECT_THAT(unlinkat(dirfd, "NewDir", AT_REMOVEDIR),
    82                SyscallFailsWithErrno(EACCES));
    83    ASSERT_THAT(close(dirfd), SyscallSucceeds());
    84  }
    85  
    86  // Files cannot be unlinked if the parent is not writable and executable.
    87  TEST(UnlinkTest, ParentDegradedPermissions) {
    88    // Drop capabilities that allow us to override file and directory permissions.
    89    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
    90    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
    91  
    92    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    93    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
    94  
    95    ASSERT_THAT(chmod(dir.path().c_str(), 0000), SyscallSucceeds());
    96  
    97    struct stat st;
    98    ASSERT_THAT(stat(file.path().c_str(), &st), SyscallFailsWithErrno(EACCES));
    99    ASSERT_THAT(unlinkat(AT_FDCWD, file.path().c_str(), 0),
   100                SyscallFailsWithErrno(EACCES));
   101  
   102    // Non-existent files also return EACCES.
   103    const std::string nonexist = JoinPath(dir.path(), "doesnotexist");
   104    ASSERT_THAT(stat(nonexist.c_str(), &st), SyscallFailsWithErrno(EACCES));
   105    ASSERT_THAT(unlinkat(AT_FDCWD, nonexist.c_str(), 0),
   106                SyscallFailsWithErrno(EACCES));
   107  }
   108  
   109  TEST(UnlinkTest, AtBad) {
   110    int dirfd;
   111    EXPECT_THAT(dirfd = open(GetAbsoluteTestTmpdir().c_str(), O_DIRECTORY, 0),
   112                SyscallSucceeds());
   113  
   114    // Try removing a directory as a file.
   115    std::string path = JoinPath(GetAbsoluteTestTmpdir(), "NewDir");
   116    EXPECT_THAT(mkdir(path.c_str(), 0755), SyscallSucceeds());
   117    EXPECT_THAT(unlinkat(dirfd, "NewDir", 0), SyscallFailsWithErrno(EISDIR));
   118    EXPECT_THAT(unlinkat(dirfd, "NewDir", AT_REMOVEDIR), SyscallSucceeds());
   119  
   120    // Try removing a file as a directory.
   121    int fd;
   122    EXPECT_THAT(fd = openat(dirfd, "UnlinkAtFile", O_RDWR | O_CREAT, 0666),
   123                SyscallSucceeds());
   124    EXPECT_THAT(unlinkat(dirfd, "UnlinkAtFile", AT_REMOVEDIR),
   125                SyscallFailsWithErrno(ENOTDIR));
   126    EXPECT_THAT(unlinkat(dirfd, "UnlinkAtFile/", 0),
   127                SyscallFailsWithErrno(ENOTDIR));
   128    ASSERT_THAT(close(fd), SyscallSucceeds());
   129    EXPECT_THAT(unlinkat(dirfd, "UnlinkAtFile", 0), SyscallSucceeds());
   130  
   131    // Cleanup.
   132    ASSERT_THAT(close(dirfd), SyscallSucceeds());
   133  }
   134  
   135  TEST(UnlinkTest, AbsTmpFile) {
   136    int fd;
   137    std::string path = JoinPath(GetAbsoluteTestTmpdir(), "ExistingFile");
   138    EXPECT_THAT(fd = open(path.c_str(), O_RDWR | O_CREAT, 0666),
   139                SyscallSucceeds());
   140    EXPECT_THAT(close(fd), SyscallSucceeds());
   141    EXPECT_THAT(unlink(path.c_str()), SyscallSucceeds());
   142  }
   143  
   144  TEST(UnlinkTest, TooLongName) {
   145    EXPECT_THAT(unlink(std::vector<char>(16384, '0').data()),
   146                SyscallFailsWithErrno(ENAMETOOLONG));
   147  }
   148  
   149  TEST(UnlinkTest, BadNamePtr) {
   150    EXPECT_THAT(unlink(reinterpret_cast<char*>(1)),
   151                SyscallFailsWithErrno(EFAULT));
   152  }
   153  
   154  TEST(UnlinkTest, AtFile) {
   155    int dirfd;
   156    EXPECT_THAT(dirfd = open(GetAbsoluteTestTmpdir().c_str(), O_DIRECTORY, 0666),
   157                SyscallSucceeds());
   158    int fd;
   159    EXPECT_THAT(fd = openat(dirfd, "UnlinkAtFile", O_RDWR | O_CREAT, 0666),
   160                SyscallSucceeds());
   161    EXPECT_THAT(close(fd), SyscallSucceeds());
   162    EXPECT_THAT(unlinkat(dirfd, "UnlinkAtFile", 0), SyscallSucceeds());
   163  }
   164  
   165  TEST(UnlinkTest, OpenFile) {
   166    // We can't save unlinked file unless they are on tmpfs.
   167    const DisableSave ds;
   168    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   169    int fd;
   170    EXPECT_THAT(fd = open(file.path().c_str(), O_RDWR, 0666), SyscallSucceeds());
   171    EXPECT_THAT(unlink(file.path().c_str()), SyscallSucceeds());
   172    EXPECT_THAT(close(fd), SyscallSucceeds());
   173  }
   174  
   175  TEST(UnlinkTest, CannotRemoveDots) {
   176    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   177    const std::string self = JoinPath(file.path(), ".");
   178    ASSERT_THAT(unlink(self.c_str()), SyscallFailsWithErrno(ENOTDIR));
   179    const std::string parent = JoinPath(file.path(), "..");
   180    ASSERT_THAT(unlink(parent.c_str()), SyscallFailsWithErrno(ENOTDIR));
   181  }
   182  
   183  TEST(UnlinkTest, CannotRemoveRoot) {
   184    ASSERT_THAT(unlinkat(-1, "/", AT_REMOVEDIR), SyscallFailsWithErrno(EBUSY));
   185  }
   186  
   187  TEST(UnlinkTest, CannotRemoveRootWithAtDir) {
   188    const FileDescriptor dirfd = ASSERT_NO_ERRNO_AND_VALUE(
   189        Open(GetAbsoluteTestTmpdir(), O_DIRECTORY, 0666));
   190    ASSERT_THAT(unlinkat(dirfd.get(), "/", AT_REMOVEDIR),
   191                SyscallFailsWithErrno(EBUSY));
   192  }
   193  
   194  TEST(RmdirTest, CannotRemoveDots) {
   195    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   196    const std::string self = JoinPath(dir.path(), ".");
   197    ASSERT_THAT(rmdir(self.c_str()), SyscallFailsWithErrno(EINVAL));
   198    const std::string parent = JoinPath(dir.path(), "..");
   199    ASSERT_THAT(rmdir(parent.c_str()), SyscallFailsWithErrno(ENOTEMPTY));
   200  }
   201  
   202  TEST(RmdirTest, CanRemoveWithTrailingSlashes) {
   203    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   204    const std::string slash = absl::StrCat(dir1.path(), "/");
   205    ASSERT_THAT(rmdir(slash.c_str()), SyscallSucceeds());
   206    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   207    const std::string slashslash = absl::StrCat(dir2.path(), "//");
   208    ASSERT_THAT(rmdir(slashslash.c_str()), SyscallSucceeds());
   209  }
   210  
   211  TEST(UnlinkTest, UnlinkAtEmptyPath) {
   212    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   213  
   214    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
   215    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR, 0666));
   216    EXPECT_THAT(unlinkat(fd.get(), "", 0), SyscallFailsWithErrno(ENOENT));
   217  
   218    auto dirInDir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path()));
   219    auto dirFD = ASSERT_NO_ERRNO_AND_VALUE(
   220        Open(dirInDir.path(), O_RDONLY | O_DIRECTORY, 0666));
   221    EXPECT_THAT(unlinkat(dirFD.get(), "", AT_REMOVEDIR),
   222                SyscallFailsWithErrno(ENOENT));
   223  }
   224  
   225  }  // namespace
   226  
   227  }  // namespace testing
   228  }  // namespace gvisor