github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/mknod.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 <sys/socket.h> 18 #include <sys/stat.h> 19 #include <sys/types.h> 20 #include <sys/un.h> 21 #include <unistd.h> 22 23 #include <vector> 24 25 #include "gtest/gtest.h" 26 #include "test/util/file_descriptor.h" 27 #include "test/util/temp_path.h" 28 #include "test/util/test_util.h" 29 #include "test/util/thread_util.h" 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 TEST(MknodTest, RegularFile) { 37 const std::string node0 = NewTempAbsPath(); 38 EXPECT_THAT(mknod(node0.c_str(), S_IFREG, 0), SyscallSucceeds()); 39 40 const std::string node1 = NewTempAbsPath(); 41 EXPECT_THAT(mknod(node1.c_str(), 0, 0), SyscallSucceeds()); 42 } 43 44 TEST(MknodTest, RegularFilePermissions) { 45 const std::string node = NewTempAbsPath(); 46 mode_t newUmask = 0077; 47 umask(newUmask); 48 49 // Attempt to open file with mode 0777. Not specifying file type should create 50 // a regualar file. 51 mode_t perms = S_IRWXU | S_IRWXG | S_IRWXO; 52 EXPECT_THAT(mknod(node.c_str(), perms, 0), SyscallSucceeds()); 53 54 // In the absence of a default ACL, the permissions of the created node are 55 // (mode & ~umask). -- mknod(2) 56 mode_t wantPerms = perms & ~newUmask; 57 struct stat st; 58 ASSERT_THAT(stat(node.c_str(), &st), SyscallSucceeds()); 59 ASSERT_EQ(st.st_mode & 0777, wantPerms); 60 61 // "Zero file type is equivalent to type S_IFREG." - mknod(2) 62 ASSERT_EQ(st.st_mode & S_IFMT, S_IFREG); 63 } 64 65 TEST(MknodTest, MknodAtFIFO) { 66 const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 67 const std::string fifo_relpath = NewTempRelPath(); 68 const std::string fifo = JoinPath(dir.path(), fifo_relpath); 69 70 const FileDescriptor dirfd = 71 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path().c_str(), O_RDONLY)); 72 ASSERT_THAT(mknodat(dirfd.get(), fifo_relpath.c_str(), S_IFIFO | S_IRUSR, 0), 73 SyscallSucceeds()); 74 75 struct stat st; 76 ASSERT_THAT(stat(fifo.c_str(), &st), SyscallSucceeds()); 77 EXPECT_TRUE(S_ISFIFO(st.st_mode)); 78 } 79 80 TEST(MknodTest, MknodOnExistingPathFails) { 81 const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); 82 const TempPath slink = ASSERT_NO_ERRNO_AND_VALUE( 83 TempPath::CreateSymlinkTo(GetAbsoluteTestTmpdir(), file.path())); 84 85 EXPECT_THAT(mknod(file.path().c_str(), S_IFREG, 0), 86 SyscallFailsWithErrno(EEXIST)); 87 EXPECT_THAT(mknod(file.path().c_str(), S_IFIFO, 0), 88 SyscallFailsWithErrno(EEXIST)); 89 EXPECT_THAT(mknod(slink.path().c_str(), S_IFREG, 0), 90 SyscallFailsWithErrno(EEXIST)); 91 EXPECT_THAT(mknod(slink.path().c_str(), S_IFIFO, 0), 92 SyscallFailsWithErrno(EEXIST)); 93 } 94 95 TEST(MknodTest, UnimplementedTypesReturnError) { 96 // TODO(gvisor.dev/issue/1624): These file types are supported by some 97 // filesystems in VFS2, so this test should be deleted along with VFS1. 98 SKIP_IF(!IsRunningWithVFS1()); 99 100 const std::string path = NewTempAbsPath(); 101 EXPECT_THAT(mknod(path.c_str(), S_IFSOCK, 0), 102 SyscallFailsWithErrno(EOPNOTSUPP)); 103 EXPECT_THAT(mknod(path.c_str(), S_IFCHR, 0), SyscallFailsWithErrno(EPERM)); 104 EXPECT_THAT(mknod(path.c_str(), S_IFBLK, 0), SyscallFailsWithErrno(EPERM)); 105 } 106 107 TEST(MknodTest, Socket) { 108 SKIP_IF(IsRunningOnGvisor() && IsRunningWithVFS1()); 109 110 ASSERT_THAT(chdir(GetAbsoluteTestTmpdir().c_str()), SyscallSucceeds()); 111 112 auto filename = NewTempRelPath(); 113 114 ASSERT_THAT(mknod(filename.c_str(), S_IFSOCK | S_IRUSR | S_IWUSR, 0), 115 SyscallSucceeds()); 116 117 int sk; 118 ASSERT_THAT(sk = socket(AF_UNIX, SOCK_SEQPACKET, 0), SyscallSucceeds()); 119 FileDescriptor fd(sk); 120 121 struct sockaddr_un addr = {.sun_family = AF_UNIX}; 122 absl::SNPrintF(addr.sun_path, sizeof(addr.sun_path), "%s", filename.c_str()); 123 ASSERT_THAT(connect(sk, (struct sockaddr *)&addr, sizeof(addr)), 124 SyscallFailsWithErrno(ECONNREFUSED)); 125 ASSERT_THAT(unlink(filename.c_str()), SyscallSucceeds()); 126 } 127 128 PosixErrorOr<FileDescriptor> OpenRetryEINTR(std::string const& path, int flags, 129 mode_t mode = 0) { 130 while (true) { 131 auto maybe_fd = Open(path, flags, mode); 132 if (maybe_fd.ok() || maybe_fd.error().errno_value() != EINTR) { 133 return maybe_fd; 134 } 135 } 136 } 137 138 TEST(MknodTest, Fifo) { 139 const std::string fifo = NewTempAbsPath(); 140 ASSERT_THAT(mknod(fifo.c_str(), S_IFIFO | S_IRUSR | S_IWUSR, 0), 141 SyscallSucceeds()); 142 143 struct stat st; 144 ASSERT_THAT(stat(fifo.c_str(), &st), SyscallSucceeds()); 145 EXPECT_TRUE(S_ISFIFO(st.st_mode)); 146 147 std::string msg = "some std::string"; 148 std::vector<char> buf(512); 149 150 // Read-end of the pipe. 151 ScopedThread t([&fifo, &buf, &msg]() { 152 FileDescriptor fd = 153 ASSERT_NO_ERRNO_AND_VALUE(OpenRetryEINTR(fifo.c_str(), O_RDONLY)); 154 EXPECT_THAT(ReadFd(fd.get(), buf.data(), buf.size()), 155 SyscallSucceedsWithValue(msg.length())); 156 EXPECT_EQ(msg, std::string(buf.data())); 157 }); 158 159 // Write-end of the pipe. 160 FileDescriptor wfd = 161 ASSERT_NO_ERRNO_AND_VALUE(OpenRetryEINTR(fifo.c_str(), O_WRONLY)); 162 EXPECT_THAT(WriteFd(wfd.get(), msg.c_str(), msg.length()), 163 SyscallSucceedsWithValue(msg.length())); 164 } 165 166 TEST(MknodTest, FifoOtrunc) { 167 const std::string fifo = NewTempAbsPath(); 168 ASSERT_THAT(mknod(fifo.c_str(), S_IFIFO | S_IRUSR | S_IWUSR, 0), 169 SyscallSucceeds()); 170 171 struct stat st = {}; 172 ASSERT_THAT(stat(fifo.c_str(), &st), SyscallSucceeds()); 173 EXPECT_TRUE(S_ISFIFO(st.st_mode)); 174 175 std::string msg = "some std::string"; 176 std::vector<char> buf(512); 177 // Read-end of the pipe. 178 ScopedThread t([&fifo, &buf, &msg]() { 179 FileDescriptor fd = 180 ASSERT_NO_ERRNO_AND_VALUE(OpenRetryEINTR(fifo.c_str(), O_RDONLY)); 181 EXPECT_THAT(ReadFd(fd.get(), buf.data(), buf.size()), 182 SyscallSucceedsWithValue(msg.length())); 183 EXPECT_EQ(msg, std::string(buf.data())); 184 }); 185 186 // Write-end of the pipe. 187 FileDescriptor wfd = ASSERT_NO_ERRNO_AND_VALUE( 188 OpenRetryEINTR(fifo.c_str(), O_WRONLY | O_TRUNC)); 189 EXPECT_THAT(WriteFd(wfd.get(), msg.c_str(), msg.length()), 190 SyscallSucceedsWithValue(msg.length())); 191 } 192 193 TEST(MknodTest, FifoTruncNoOp) { 194 const std::string fifo = NewTempAbsPath(); 195 ASSERT_THAT(mknod(fifo.c_str(), S_IFIFO | S_IRUSR | S_IWUSR, 0), 196 SyscallSucceeds()); 197 198 EXPECT_THAT(truncate(fifo.c_str(), 0), SyscallFailsWithErrno(EINVAL)); 199 200 struct stat st = {}; 201 ASSERT_THAT(stat(fifo.c_str(), &st), SyscallSucceeds()); 202 EXPECT_TRUE(S_ISFIFO(st.st_mode)); 203 204 std::string msg = "some std::string"; 205 std::vector<char> buf(512); 206 // Read-end of the pipe. 207 ScopedThread t([&fifo, &buf, &msg]() { 208 FileDescriptor fd = 209 ASSERT_NO_ERRNO_AND_VALUE(OpenRetryEINTR(fifo.c_str(), O_RDONLY)); 210 EXPECT_THAT(ReadFd(fd.get(), buf.data(), buf.size()), 211 SyscallSucceedsWithValue(msg.length())); 212 EXPECT_EQ(msg, std::string(buf.data())); 213 }); 214 215 FileDescriptor wfd = ASSERT_NO_ERRNO_AND_VALUE( 216 OpenRetryEINTR(fifo.c_str(), O_WRONLY | O_TRUNC)); 217 EXPECT_THAT(ftruncate(wfd.get(), 0), SyscallFailsWithErrno(EINVAL)); 218 EXPECT_THAT(WriteFd(wfd.get(), msg.c_str(), msg.length()), 219 SyscallSucceedsWithValue(msg.length())); 220 EXPECT_THAT(ftruncate(wfd.get(), 0), SyscallFailsWithErrno(EINVAL)); 221 } 222 223 TEST(MknodTest, MknodAtEmptyPath) { 224 auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); 225 auto fd = 226 ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY | O_DIRECTORY, 0666)); 227 EXPECT_THAT(mknodat(fd.get(), "", S_IFREG | 0777, 0), 228 SyscallFailsWithErrno(ENOENT)); 229 } 230 231 } // namespace 232 233 } // namespace testing 234 } // namespace gvisor