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