gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/pselect.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 <signal.h>
    16  #include <sys/select.h>
    17  
    18  #include "gtest/gtest.h"
    19  #include "absl/time/time.h"
    20  #include "test/syscalls/linux/base_poll_test.h"
    21  #include "test/util/signal_util.h"
    22  #include "test/util/test_util.h"
    23  
    24  namespace gvisor {
    25  namespace testing {
    26  namespace {
    27  
    28  struct MaskWithSize {
    29    sigset_t* mask;
    30    size_t mask_size;
    31  };
    32  
    33  // Linux and glibc have a different idea of the sizeof sigset_t. When calling
    34  // the syscall directly, use what the kernel expects.
    35  unsigned kSigsetSize = SIGRTMAX / 8;
    36  
    37  // Linux pselect(2) differs from the glibc wrapper function in that Linux
    38  // updates the timeout with the amount of time remaining. In order to test this
    39  // behavior we need to use the syscall directly.
    40  int syscallPselect6(int nfds, fd_set* readfds, fd_set* writefds,
    41                      fd_set* exceptfds, struct timespec* timeout,
    42                      const MaskWithSize* mask_with_size) {
    43    return syscall(SYS_pselect6, nfds, readfds, writefds, exceptfds, timeout,
    44                   mask_with_size);
    45  }
    46  
    47  class PselectTest : public BasePollTest {
    48   protected:
    49    void SetUp() override { BasePollTest::SetUp(); }
    50    void TearDown() override { BasePollTest::TearDown(); }
    51  };
    52  
    53  // See that when there are no FD sets, pselect behaves like sleep.
    54  TEST_F(PselectTest, NullFds) {
    55    struct timespec timeout = absl::ToTimespec(absl::Milliseconds(10));
    56    ASSERT_THAT(syscallPselect6(0, nullptr, nullptr, nullptr, &timeout, nullptr),
    57                SyscallSucceeds());
    58    EXPECT_EQ(timeout.tv_sec, 0);
    59    EXPECT_EQ(timeout.tv_nsec, 0);
    60  
    61    timeout = absl::ToTimespec(absl::Milliseconds(10));
    62    ASSERT_THAT(syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, nullptr),
    63                SyscallSucceeds());
    64    EXPECT_EQ(timeout.tv_sec, 0);
    65    EXPECT_EQ(timeout.tv_nsec, 0);
    66  }
    67  
    68  TEST_F(PselectTest, ClosedFds) {
    69    fd_set read_set;
    70    FD_ZERO(&read_set);
    71    int fd;
    72    ASSERT_THAT(fd = dup(1), SyscallSucceeds());
    73    ASSERT_THAT(close(fd), SyscallSucceeds());
    74    FD_SET(fd, &read_set);
    75    struct timespec timeout = absl::ToTimespec(absl::Milliseconds(10));
    76    EXPECT_THAT(
    77        syscallPselect6(fd + 1, &read_set, nullptr, nullptr, &timeout, nullptr),
    78        SyscallFailsWithErrno(EBADF));
    79  }
    80  
    81  TEST_F(PselectTest, ZeroTimeout) {
    82    struct timespec timeout = {};
    83    ASSERT_THAT(syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, nullptr),
    84                SyscallSucceeds());
    85    EXPECT_EQ(timeout.tv_sec, 0);
    86    EXPECT_EQ(timeout.tv_nsec, 0);
    87  }
    88  
    89  // If random S/R interrupts the pselect, SIGALRM may be delivered before pselect
    90  // restarts, causing the pselect to hang forever.
    91  TEST_F(PselectTest, NoTimeout) {
    92    // When there's no timeout, pselect may never return so set a timer.
    93    SetTimer(absl::Milliseconds(100));
    94    // See that we get interrupted by the timer.
    95    ASSERT_THAT(syscallPselect6(1, nullptr, nullptr, nullptr, nullptr, nullptr),
    96                SyscallFailsWithErrno(EINTR));
    97    EXPECT_TRUE(TimerFired());
    98  }
    99  
   100  TEST_F(PselectTest, InvalidTimeoutNegative) {
   101    struct timespec timeout = absl::ToTimespec(absl::Seconds(-1));
   102    ASSERT_THAT(syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, nullptr),
   103                SyscallFailsWithErrno(EINVAL));
   104    EXPECT_EQ(timeout.tv_sec, -1);
   105    EXPECT_EQ(timeout.tv_nsec, 0);
   106  }
   107  
   108  TEST_F(PselectTest, InvalidTimeoutNotNormalized) {
   109    struct timespec timeout = {0, 1000000001};
   110    ASSERT_THAT(syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, nullptr),
   111                SyscallFailsWithErrno(EINVAL));
   112    EXPECT_EQ(timeout.tv_sec, 0);
   113    EXPECT_EQ(timeout.tv_nsec, 1000000001);
   114  }
   115  
   116  TEST_F(PselectTest, EmptySigMaskInvalidMaskSize) {
   117    struct timespec timeout = {};
   118    MaskWithSize invalid = {nullptr, 7};
   119    EXPECT_THAT(syscallPselect6(0, nullptr, nullptr, nullptr, &timeout, &invalid),
   120                SyscallSucceeds());
   121  }
   122  
   123  TEST_F(PselectTest, EmptySigMaskValidMaskSize) {
   124    struct timespec timeout = {};
   125    MaskWithSize invalid = {nullptr, 8};
   126    EXPECT_THAT(syscallPselect6(0, nullptr, nullptr, nullptr, &timeout, &invalid),
   127                SyscallSucceeds());
   128  }
   129  
   130  TEST_F(PselectTest, InvalidMaskSize) {
   131    struct timespec timeout = {};
   132    sigset_t sigmask;
   133    ASSERT_THAT(sigemptyset(&sigmask), SyscallSucceeds());
   134    MaskWithSize invalid = {&sigmask, 7};
   135    EXPECT_THAT(syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, &invalid),
   136                SyscallFailsWithErrno(EINVAL));
   137  }
   138  
   139  // Verify that signals blocked by the pselect mask (that would otherwise be
   140  // allowed) do not interrupt pselect.
   141  TEST_F(PselectTest, SignalMaskBlocksSignal) {
   142    absl::Duration duration(absl::Seconds(30));
   143    struct timespec timeout = absl::ToTimespec(duration);
   144    absl::Duration timer_duration(absl::Seconds(10));
   145  
   146    // Call with a mask that blocks SIGALRM. See that pselect is not interrupted
   147    // (i.e. returns 0) and that upon completion, the timer has fired.
   148    sigset_t mask;
   149    ASSERT_THAT(sigprocmask(0, nullptr, &mask), SyscallSucceeds());
   150    ASSERT_THAT(sigaddset(&mask, SIGALRM), SyscallSucceeds());
   151    MaskWithSize mask_with_size = {&mask, kSigsetSize};
   152    SetTimer(timer_duration);
   153    MaybeSave();
   154    ASSERT_FALSE(TimerFired());
   155    ASSERT_THAT(
   156        syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, &mask_with_size),
   157        SyscallSucceeds());
   158    EXPECT_TRUE(TimerFired());
   159    EXPECT_EQ(absl::DurationFromTimespec(timeout), absl::Duration());
   160  }
   161  
   162  // Verify that signals allowed by the pselect mask (that would otherwise be
   163  // blocked) interrupt pselect.
   164  TEST_F(PselectTest, SignalMaskAllowsSignal) {
   165    absl::Duration duration = absl::Seconds(30);
   166    struct timespec timeout = absl::ToTimespec(duration);
   167    absl::Duration timer_duration = absl::Seconds(10);
   168  
   169    sigset_t mask;
   170    ASSERT_THAT(sigprocmask(0, nullptr, &mask), SyscallSucceeds());
   171  
   172    // Block SIGALRM.
   173    auto cleanup =
   174        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, SIGALRM));
   175  
   176    // Call with a mask that unblocks SIGALRM. See that pselect is interrupted.
   177    MaskWithSize mask_with_size = {&mask, kSigsetSize};
   178    SetTimer(timer_duration);
   179    MaybeSave();
   180    ASSERT_FALSE(TimerFired());
   181    ASSERT_THAT(
   182        syscallPselect6(1, nullptr, nullptr, nullptr, &timeout, &mask_with_size),
   183        SyscallFailsWithErrno(EINTR));
   184    EXPECT_TRUE(TimerFired());
   185    EXPECT_GT(absl::DurationFromTimespec(timeout), absl::Duration());
   186  }
   187  
   188  }  // namespace
   189  }  // namespace testing
   190  }  // namespace gvisor