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