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 = &ifr;
   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