github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/dup.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 <unistd.h> 17 18 #include "gtest/gtest.h" 19 #include "test/util/eventfd_util.h" 20 #include "test/util/file_descriptor.h" 21 #include "test/util/fs_util.h" 22 #include "test/util/posix_error.h" 23 #include "test/util/temp_path.h" 24 #include "test/util/test_util.h" 25 26 namespace gvisor { 27 namespace testing { 28 29 namespace { 30 31 PosixErrorOr<FileDescriptor> Dup2(const FileDescriptor& fd, int target_fd) { 32 int new_fd = dup2(fd.get(), target_fd); 33 if (new_fd < 0) { 34 return PosixError(errno, "Dup2"); 35 } 36 return FileDescriptor(new_fd); 37 } 38 39 PosixErrorOr<FileDescriptor> Dup3(const FileDescriptor& fd, int target_fd, 40 int flags) { 41 int new_fd = dup3(fd.get(), target_fd, flags); 42 if (new_fd < 0) { 43 return PosixError(errno, "Dup2"); 44 } 45 return FileDescriptor(new_fd); 46 } 47 48 TEST(DupTest, Dup) { 49 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 50 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY)); 51 52 // Dup the descriptor and make sure it's the same file. 53 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 54 ASSERT_NE(fd.get(), nfd.get()); 55 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 56 } 57 58 TEST(DupTest, DupClearsCloExec) { 59 // Open an eventfd file descriptor with FD_CLOEXEC descriptor flag set. 60 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_CLOEXEC)); 61 EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC)); 62 63 // Duplicate the descriptor. Ensure that it doesn't have FD_CLOEXEC set. 64 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 65 ASSERT_NE(fd.get(), nfd.get()); 66 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 67 EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(0)); 68 } 69 70 TEST(DupTest, DupWithOpath) { 71 SKIP_IF(IsRunningWithVFS1()); 72 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 73 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_PATH)); 74 int flags; 75 ASSERT_THAT(flags = fcntl(fd.get(), F_GETFL), SyscallSucceeds()); 76 77 // Dup the descriptor and make sure it's the same file. 78 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 79 ASSERT_NE(fd.get(), nfd.get()); 80 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 81 EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags)); 82 } 83 84 TEST(DupTest, Dup2) { 85 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 86 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY)); 87 88 // Regular dup once. 89 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 90 91 ASSERT_NE(fd.get(), nfd.get()); 92 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 93 94 // Dup over the file above. 95 int target_fd = nfd.release(); 96 FileDescriptor nfd2 = ASSERT_NO_ERRNO_AND_VALUE(Dup2(fd, target_fd)); 97 EXPECT_EQ(target_fd, nfd2.get()); 98 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd2)); 99 } 100 101 TEST(DupTest, Dup2SameFD) { 102 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 103 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY)); 104 105 // Should succeed. 106 ASSERT_THAT(dup2(fd.get(), fd.get()), SyscallSucceedsWithValue(fd.get())); 107 } 108 109 TEST(DupTest, Dup2WithOpath) { 110 SKIP_IF(IsRunningWithVFS1()); 111 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 112 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_PATH)); 113 int flags; 114 ASSERT_THAT(flags = fcntl(fd.get(), F_GETFL), SyscallSucceeds()); 115 116 // Regular dup once. 117 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 118 119 ASSERT_NE(fd.get(), nfd.get()); 120 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 121 EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags)); 122 123 // Dup over the file above. 124 int target_fd = nfd.release(); 125 FileDescriptor nfd2 = ASSERT_NO_ERRNO_AND_VALUE(Dup2(fd, target_fd)); 126 EXPECT_EQ(target_fd, nfd2.get()); 127 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd2)); 128 EXPECT_THAT(fcntl(nfd2.get(), F_GETFL), SyscallSucceedsWithValue(flags)); 129 } 130 131 TEST(DupTest, Dup3) { 132 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 133 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY)); 134 135 // Regular dup once. 136 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 137 ASSERT_NE(fd.get(), nfd.get()); 138 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 139 140 // Dup over the file above, check that it has no CLOEXEC. 141 nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), 0)); 142 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 143 EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(0)); 144 145 // Dup over the file again, check that it does not CLOEXEC. 146 nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), O_CLOEXEC)); 147 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 148 EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC)); 149 } 150 151 TEST(DupTest, Dup3FailsSameFD) { 152 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 153 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY)); 154 155 // Only dup3 fails if the new and old fd are the same. 156 ASSERT_THAT(dup3(fd.get(), fd.get(), 0), SyscallFailsWithErrno(EINVAL)); 157 } 158 159 TEST(DupTest, Dup3WithOpath) { 160 SKIP_IF(IsRunningWithVFS1()); 161 auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 162 FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_PATH)); 163 EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(0)); 164 int flags; 165 ASSERT_THAT(flags = fcntl(fd.get(), F_GETFL), SyscallSucceeds()); 166 167 // Regular dup once. 168 FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup()); 169 ASSERT_NE(fd.get(), nfd.get()); 170 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 171 172 // Dup over the file above, check that it has no CLOEXEC. 173 nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), 0)); 174 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 175 EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(0)); 176 EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags)); 177 178 // Dup over the file again, check that it does not CLOEXEC. 179 nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), O_CLOEXEC)); 180 ASSERT_NO_ERRNO(CheckSameFile(fd, nfd)); 181 EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC)); 182 EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags)); 183 } 184 185 } // namespace 186 187 } // namespace testing 188 } // namespace gvisor