github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/ioctl.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 <arpa/inet.h> 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <net/if.h> 19 #include <netdb.h> 20 #include <signal.h> 21 #include <sys/ioctl.h> 22 #include <sys/socket.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 28 #include "test/syscalls/linux/ip_socket_test_util.h" 29 #include "test/syscalls/linux/socket_test_util.h" 30 #include "test/syscalls/linux/unix_domain_socket_test_util.h" 31 #include "test/util/file_descriptor.h" 32 #include "test/util/signal_util.h" 33 #include "test/util/test_util.h" 34 35 namespace gvisor { 36 namespace testing { 37 38 namespace { 39 40 bool CheckNonBlocking(int fd) { 41 int ret = fcntl(fd, F_GETFL, 0); 42 TEST_CHECK(ret != -1); 43 return (ret & O_NONBLOCK) == O_NONBLOCK; 44 } 45 46 bool CheckCloExec(int fd) { 47 int ret = fcntl(fd, F_GETFD, 0); 48 TEST_CHECK(ret != -1); 49 return (ret & FD_CLOEXEC) == FD_CLOEXEC; 50 } 51 52 class IoctlTest : public ::testing::Test { 53 protected: 54 void SetUp() override { 55 ASSERT_THAT(fd_ = open("/dev/null", O_RDONLY), SyscallSucceeds()); 56 } 57 58 void TearDown() override { 59 if (fd_ >= 0) { 60 ASSERT_THAT(close(fd_), SyscallSucceeds()); 61 fd_ = -1; 62 } 63 } 64 65 int fd() const { return fd_; } 66 67 private: 68 int fd_ = -1; 69 }; 70 71 TEST_F(IoctlTest, BadFileDescriptor) { 72 EXPECT_THAT(ioctl(-1 /* fd */, 0), SyscallFailsWithErrno(EBADF)); 73 } 74 75 TEST_F(IoctlTest, InvalidControlNumber) { 76 EXPECT_THAT(ioctl(STDOUT_FILENO, 0), SyscallFailsWithErrno(ENOTTY)); 77 } 78 79 TEST_F(IoctlTest, IoctlWithOpath) { 80 SKIP_IF(IsRunningWithVFS1()); 81 const FileDescriptor fd = 82 ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/null", O_PATH)); 83 84 int set = 1; 85 EXPECT_THAT(ioctl(fd.get(), FIONBIO, &set), SyscallFailsWithErrno(EBADF)); 86 87 EXPECT_THAT(ioctl(fd.get(), FIONCLEX), SyscallFailsWithErrno(EBADF)); 88 89 EXPECT_THAT(ioctl(fd.get(), FIOCLEX), SyscallFailsWithErrno(EBADF)); 90 } 91 92 TEST_F(IoctlTest, FIONBIOSucceeds) { 93 EXPECT_FALSE(CheckNonBlocking(fd())); 94 int set = 1; 95 EXPECT_THAT(ioctl(fd(), FIONBIO, &set), SyscallSucceeds()); 96 EXPECT_TRUE(CheckNonBlocking(fd())); 97 set = 0; 98 EXPECT_THAT(ioctl(fd(), FIONBIO, &set), SyscallSucceeds()); 99 EXPECT_FALSE(CheckNonBlocking(fd())); 100 } 101 102 TEST_F(IoctlTest, FIONBIOFails) { 103 EXPECT_THAT(ioctl(fd(), FIONBIO, nullptr), SyscallFailsWithErrno(EFAULT)); 104 } 105 106 TEST_F(IoctlTest, FIONCLEXSucceeds) { 107 EXPECT_THAT(ioctl(fd(), FIONCLEX), SyscallSucceeds()); 108 EXPECT_FALSE(CheckCloExec(fd())); 109 } 110 111 TEST_F(IoctlTest, FIOCLEXSucceeds) { 112 EXPECT_THAT(ioctl(fd(), FIOCLEX), SyscallSucceeds()); 113 EXPECT_TRUE(CheckCloExec(fd())); 114 } 115 116 TEST_F(IoctlTest, FIOASYNCFails) { 117 EXPECT_THAT(ioctl(fd(), FIOASYNC, nullptr), SyscallFailsWithErrno(EFAULT)); 118 } 119 120 TEST_F(IoctlTest, FIOASYNCSucceeds) { 121 // Not all FDs support FIOASYNC. 122 const FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE( 123 Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); 124 125 int before = -1; 126 ASSERT_THAT(before = fcntl(s.get(), F_GETFL), SyscallSucceeds()); 127 128 int set = 1; 129 EXPECT_THAT(ioctl(s.get(), FIOASYNC, &set), SyscallSucceeds()); 130 131 int after_set = -1; 132 ASSERT_THAT(after_set = fcntl(s.get(), F_GETFL), SyscallSucceeds()); 133 EXPECT_EQ(after_set, before | O_ASYNC) << "before was " << before; 134 135 set = 0; 136 EXPECT_THAT(ioctl(s.get(), FIOASYNC, &set), SyscallSucceeds()); 137 138 ASSERT_THAT(fcntl(s.get(), F_GETFL), SyscallSucceedsWithValue(before)); 139 } 140 141 /* Count of the number of SIGIOs handled. */ 142 static volatile int io_received = 0; 143 144 void inc_io_handler(int sig, siginfo_t* siginfo, void* arg) { io_received++; } 145 146 TEST_F(IoctlTest, FIOASYNCNoTarget) { 147 auto pair = 148 ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); 149 150 // Count SIGIOs received. 151 io_received = 0; 152 struct sigaction sa; 153 sa.sa_sigaction = inc_io_handler; 154 sigfillset(&sa.sa_mask); 155 sa.sa_flags = SA_RESTART; 156 auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 157 158 // Actually allow SIGIO delivery. 159 auto mask_cleanup = 160 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO)); 161 162 int set = 1; 163 EXPECT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); 164 165 constexpr char kData[] = "abc"; 166 ASSERT_THAT(WriteFd(pair->first_fd(), kData, sizeof(kData)), 167 SyscallSucceedsWithValue(sizeof(kData))); 168 169 EXPECT_EQ(io_received, 0); 170 } 171 172 TEST_F(IoctlTest, FIOASYNCSelfTarget) { 173 // FIXME(b/120624367): gVisor erroneously sends SIGIO on close(2), which would 174 // kill the test when pair goes out of scope. Temporarily ignore SIGIO so that 175 // that the close signal is ignored. 176 struct sigaction sa; 177 sa.sa_handler = SIG_IGN; 178 auto early_sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 179 180 auto pair = 181 ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); 182 183 // Count SIGIOs received. 184 io_received = 0; 185 sa.sa_sigaction = inc_io_handler; 186 sigfillset(&sa.sa_mask); 187 sa.sa_flags = SA_RESTART; 188 auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 189 190 // Actually allow SIGIO delivery. 191 auto mask_cleanup = 192 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO)); 193 194 int set = 1; 195 EXPECT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); 196 197 pid_t pid = getpid(); 198 EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds()); 199 200 constexpr char kData[] = "abc"; 201 ASSERT_THAT(WriteFd(pair->first_fd(), kData, sizeof(kData)), 202 SyscallSucceedsWithValue(sizeof(kData))); 203 204 EXPECT_EQ(io_received, 1); 205 } 206 207 // Equivalent to FIOASYNCSelfTarget except that FIOSETOWN is called before 208 // FIOASYNC. 209 TEST_F(IoctlTest, FIOASYNCSelfTarget2) { 210 // FIXME(b/120624367): gVisor erroneously sends SIGIO on close(2), which would 211 // kill the test when pair goes out of scope. Temporarily ignore SIGIO so that 212 // that the close signal is ignored. 213 struct sigaction sa; 214 sa.sa_handler = SIG_IGN; 215 auto early_sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 216 217 auto pair = 218 ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); 219 220 // Count SIGIOs received. 221 io_received = 0; 222 sa.sa_sigaction = inc_io_handler; 223 sigfillset(&sa.sa_mask); 224 sa.sa_flags = SA_RESTART; 225 auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 226 227 // Actually allow SIGIO delivery. 228 auto mask_cleanup = 229 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO)); 230 231 pid_t pid = -1; 232 EXPECT_THAT(pid = getpid(), SyscallSucceeds()); 233 EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds()); 234 235 int set = 1; 236 EXPECT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); 237 238 constexpr char kData[] = "abc"; 239 ASSERT_THAT(WriteFd(pair->first_fd(), kData, sizeof(kData)), 240 SyscallSucceedsWithValue(sizeof(kData))); 241 242 EXPECT_EQ(io_received, 1); 243 } 244 245 // Check that closing an FD does not result in an event. 246 TEST_F(IoctlTest, FIOASYNCSelfTargetClose) { 247 // Count SIGIOs received. 248 struct sigaction sa; 249 io_received = 0; 250 sa.sa_sigaction = inc_io_handler; 251 sigfillset(&sa.sa_mask); 252 sa.sa_flags = SA_RESTART; 253 auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 254 255 // Actually allow SIGIO delivery. 256 auto mask_cleanup = 257 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO)); 258 259 for (int i = 0; i < 2; i++) { 260 auto pair = ASSERT_NO_ERRNO_AND_VALUE( 261 UnixDomainSocketPair(SOCK_SEQPACKET).Create()); 262 263 pid_t pid = getpid(); 264 EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds()); 265 266 int set = 1; 267 EXPECT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); 268 } 269 270 // FIXME(b/120624367): gVisor erroneously sends SIGIO on close. 271 SKIP_IF(IsRunningOnGvisor()); 272 273 EXPECT_EQ(io_received, 0); 274 } 275 276 TEST_F(IoctlTest, FIOASYNCInvalidPID) { 277 auto pair = 278 ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); 279 int set = 1; 280 ASSERT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); 281 pid_t pid = INT_MAX; 282 // This succeeds (with behavior equivalent to a pid of 0) in Linux prior to 283 // f73127356f34 "fs/fcntl: return -ESRCH in f_setown when pid/pgid can't be 284 // found", and fails with EPERM after that commit. 285 EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), 286 AnyOf(SyscallSucceeds(), SyscallFailsWithErrno(ESRCH))); 287 } 288 289 TEST_F(IoctlTest, FIOASYNCUnsetTarget) { 290 auto pair = 291 ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); 292 293 // Count SIGIOs received. 294 io_received = 0; 295 struct sigaction sa; 296 sa.sa_sigaction = inc_io_handler; 297 sigfillset(&sa.sa_mask); 298 sa.sa_flags = SA_RESTART; 299 auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); 300 301 // Actually allow SIGIO delivery. 302 auto mask_cleanup = 303 ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO)); 304 305 int set = 1; 306 EXPECT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); 307 308 pid_t pid = getpid(); 309 EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds()); 310 311 // Passing a PID of 0 unsets the target. 312 pid = 0; 313 EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds()); 314 315 constexpr char kData[] = "abc"; 316 ASSERT_THAT(WriteFd(pair->first_fd(), kData, sizeof(kData)), 317 SyscallSucceedsWithValue(sizeof(kData))); 318 319 EXPECT_EQ(io_received, 0); 320 } 321 322 using IoctlTestSIOCGIFCONF = SimpleSocketTest; 323 324 TEST_P(IoctlTestSIOCGIFCONF, ValidateNoArrayGetsLength) { 325 auto fd = ASSERT_NO_ERRNO_AND_VALUE(NewSocket()); 326 327 // Validate that no array can be used to get the length required. 328 struct ifconf ifconf = {}; 329 ASSERT_THAT(ioctl(fd->get(), SIOCGIFCONF, &ifconf), SyscallSucceeds()); 330 ASSERT_GT(ifconf.ifc_len, 0); 331 } 332 333 // This test validates that we will only return a partial array list and not 334 // partial ifrreq structs. 335 TEST_P(IoctlTestSIOCGIFCONF, ValidateNoPartialIfrsReturned) { 336 auto fd = ASSERT_NO_ERRNO_AND_VALUE(NewSocket()); 337 338 struct ifreq ifr = {}; 339 struct ifconf ifconf = {}; 340 ifconf.ifc_len = sizeof(ifr) - 1; // One byte too few. 341 ifconf.ifc_ifcu.ifcu_req = 𝔦 342 343 ASSERT_THAT(ioctl(fd->get(), SIOCGIFCONF, &ifconf), SyscallSucceeds()); 344 ASSERT_EQ(ifconf.ifc_len, 0); 345 ASSERT_EQ(ifr.ifr_name[0], '\0'); // Nothing is returned. 346 347 ifconf.ifc_len = sizeof(ifreq); 348 ASSERT_THAT(ioctl(fd->get(), SIOCGIFCONF, &ifconf), SyscallSucceeds()); 349 ASSERT_GT(ifconf.ifc_len, 0); 350 ASSERT_NE(ifr.ifr_name[0], '\0'); // An interface can now be returned. 351 } 352 353 TEST_P(IoctlTestSIOCGIFCONF, ValidateLoopbackIsPresent) { 354 auto fd = ASSERT_NO_ERRNO_AND_VALUE(NewSocket()); 355 356 struct ifconf ifconf = {}; 357 struct ifreq ifr[10] = {}; // Storage for up to 10 interfaces. 358 359 ifconf.ifc_req = ifr; 360 ifconf.ifc_len = sizeof(ifr); 361 362 ASSERT_THAT(ioctl(fd->get(), SIOCGIFCONF, &ifconf), SyscallSucceeds()); 363 size_t num_if = ifconf.ifc_len / sizeof(struct ifreq); 364 365 // We should have at least one interface. 366 ASSERT_GE(num_if, 1); 367 368 // One of the interfaces should be a loopback. 369 bool found_loopback = false; 370 for (size_t i = 0; i < num_if; ++i) { 371 if (strcmp(ifr[i].ifr_name, "lo") == 0) { 372 // SIOCGIFCONF returns the ipv4 address of the interface, let's check it. 373 ASSERT_EQ(ifr[i].ifr_addr.sa_family, AF_INET); 374 375 // Validate the address is correct for loopback. 376 sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ifr[i].ifr_addr); 377 ASSERT_EQ(htonl(sin->sin_addr.s_addr), INADDR_LOOPBACK); 378 379 found_loopback = true; 380 break; 381 } 382 } 383 ASSERT_TRUE(found_loopback); 384 } 385 386 std::vector<SocketKind> IoctlSocketTypes() { 387 return {SimpleSocket(AF_UNIX, SOCK_STREAM, 0), 388 SimpleSocket(AF_UNIX, SOCK_DGRAM, 0), 389 SimpleSocket(AF_INET, SOCK_STREAM, 0), 390 SimpleSocket(AF_INET6, SOCK_STREAM, 0), 391 SimpleSocket(AF_INET, SOCK_DGRAM, 0), 392 SimpleSocket(AF_INET6, SOCK_DGRAM, 0)}; 393 } 394 395 INSTANTIATE_TEST_SUITE_P(IoctlTest, IoctlTestSIOCGIFCONF, 396 ::testing::ValuesIn(IoctlSocketTypes())); 397 398 } // namespace 399 400 TEST_F(IoctlTest, FIOGETOWNSucceeds) { 401 const FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE( 402 Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); 403 404 int get = -1; 405 ASSERT_THAT(ioctl(s.get(), FIOGETOWN, &get), SyscallSucceeds()); 406 EXPECT_EQ(get, 0); 407 } 408 409 TEST_F(IoctlTest, SIOCGPGRPSucceeds) { 410 const FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE( 411 Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); 412 413 int get = -1; 414 ASSERT_THAT(ioctl(s.get(), SIOCGPGRP, &get), SyscallSucceeds()); 415 EXPECT_EQ(get, 0); 416 } 417 418 } // namespace testing 419 } // namespace gvisor