gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/signalfd.cc (about)

     1  // Copyright 2019 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 <errno.h>
    16  #include <poll.h>
    17  #include <signal.h>
    18  #include <stdio.h>
    19  #include <string.h>
    20  #include <sys/signalfd.h>
    21  #include <unistd.h>
    22  
    23  #include <functional>
    24  #include <vector>
    25  
    26  #include "gtest/gtest.h"
    27  #include "absl/synchronization/mutex.h"
    28  #include "test/util/file_descriptor.h"
    29  #include "test/util/posix_error.h"
    30  #include "test/util/signal_util.h"
    31  #include "test/util/test_util.h"
    32  #include "test/util/thread_util.h"
    33  
    34  using ::testing::KilledBySignal;
    35  
    36  namespace gvisor {
    37  namespace testing {
    38  
    39  namespace {
    40  
    41  constexpr int kSigno = SIGUSR1;
    42  constexpr int kSignoMax = 64;  // SIGRTMAX
    43  constexpr int kSignoAlt = SIGUSR2;
    44  
    45  class SignalfdTest : public ::testing::TestWithParam<int> {};
    46  
    47  TEST_P(SignalfdTest, Basic) {
    48    int signo = GetParam();
    49    // Create the signalfd.
    50    sigset_t mask;
    51    sigemptyset(&mask);
    52    sigaddset(&mask, signo);
    53    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0));
    54  
    55    // Deliver the blocked signal.
    56    const auto scoped_sigmask =
    57        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo));
    58    ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds());
    59  
    60    // We should now read the signal.
    61    struct signalfd_siginfo rbuf;
    62    ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
    63                SyscallSucceedsWithValue(sizeof(rbuf)));
    64    EXPECT_EQ(rbuf.ssi_signo, signo);
    65  }
    66  
    67  TEST_P(SignalfdTest, MaskWorks) {
    68    int signo = GetParam();
    69    // Create two signalfds with different masks.
    70    sigset_t mask1, mask2;
    71    sigemptyset(&mask1);
    72    sigemptyset(&mask2);
    73    sigaddset(&mask1, signo);
    74    sigaddset(&mask2, kSignoAlt);
    75    FileDescriptor fd1 = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask1, 0));
    76    FileDescriptor fd2 = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask2, 0));
    77  
    78    // Deliver the two signals.
    79    const auto scoped_sigmask1 =
    80        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo));
    81    const auto scoped_sigmask2 =
    82        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, kSignoAlt));
    83    ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds());
    84    ASSERT_THAT(tgkill(getpid(), gettid(), kSignoAlt), SyscallSucceeds());
    85  
    86    // We should see the signals on the appropriate signalfds.
    87    //
    88    // We read in the opposite order as the signals deliver above, to ensure that
    89    // we don't happen to read the correct signal from the correct signalfd.
    90    struct signalfd_siginfo rbuf1, rbuf2;
    91    ASSERT_THAT(read(fd2.get(), &rbuf2, sizeof(rbuf2)),
    92                SyscallSucceedsWithValue(sizeof(rbuf2)));
    93    EXPECT_EQ(rbuf2.ssi_signo, kSignoAlt);
    94    ASSERT_THAT(read(fd1.get(), &rbuf1, sizeof(rbuf1)),
    95                SyscallSucceedsWithValue(sizeof(rbuf1)));
    96    EXPECT_EQ(rbuf1.ssi_signo, signo);
    97  }
    98  
    99  TEST(Signalfd, Cloexec) {
   100    // Exec tests confirm that O_CLOEXEC has the intended effect. We just create a
   101    // signalfd with the appropriate flag here and assert that the FD has it set.
   102    sigset_t mask;
   103    sigemptyset(&mask);
   104    FileDescriptor fd =
   105        ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC));
   106    EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC));
   107  }
   108  
   109  TEST_P(SignalfdTest, Blocking) {
   110    int signo = GetParam();
   111    // Create the signalfd in blocking mode.
   112    sigset_t mask;
   113    sigemptyset(&mask);
   114    sigaddset(&mask, signo);
   115    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0));
   116  
   117    // Shared tid variable.
   118    absl::Mutex mu;
   119    bool has_tid = false;
   120    pid_t tid;
   121  
   122    // Start a thread reading.
   123    ScopedThread t([&] {
   124      // Copy the tid and notify the caller.
   125      {
   126        absl::MutexLock ml(&mu);
   127        tid = gettid();
   128        has_tid = true;
   129      }
   130  
   131      // Read the signal from the signalfd.
   132      struct signalfd_siginfo rbuf;
   133      ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   134                  SyscallSucceedsWithValue(sizeof(rbuf)));
   135      EXPECT_EQ(rbuf.ssi_signo, signo);
   136    });
   137  
   138    // Wait until blocked.
   139    absl::MutexLock ml(&mu);
   140    mu.Await(absl::Condition(&has_tid));
   141  
   142    // Deliver the signal to either the waiting thread, or
   143    // to this thread. N.B. this is a bug in the core gVisor
   144    // behavior for signalfd, and needs to be fixed.
   145    //
   146    // See gvisor.dev/issue/139.
   147    if (IsRunningOnGvisor()) {
   148      ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds());
   149    } else {
   150      ASSERT_THAT(tgkill(getpid(), tid, signo), SyscallSucceeds());
   151    }
   152  
   153    // Ensure that it was received.
   154    t.Join();
   155  }
   156  
   157  TEST_P(SignalfdTest, ThreadGroup) {
   158    int signo = GetParam();
   159    // Create the signalfd in blocking mode.
   160    sigset_t mask;
   161    sigemptyset(&mask);
   162    sigaddset(&mask, signo);
   163    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0));
   164  
   165    // Shared variable.
   166    absl::Mutex mu;
   167    bool first = false;
   168    bool second = false;
   169  
   170    // Start a thread reading.
   171    ScopedThread t([&] {
   172      // Read the signal from the signalfd.
   173      struct signalfd_siginfo rbuf;
   174      ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   175                  SyscallSucceedsWithValue(sizeof(rbuf)));
   176      EXPECT_EQ(rbuf.ssi_signo, signo);
   177  
   178      // Wait for the other thread.
   179      absl::MutexLock ml(&mu);
   180      first = true;
   181      mu.Await(absl::Condition(&second));
   182    });
   183  
   184    // Deliver the signal to the threadgroup.
   185    ASSERT_THAT(kill(getpid(), signo), SyscallSucceeds());
   186  
   187    // Wait for the first thread to process.
   188    {
   189      absl::MutexLock ml(&mu);
   190      mu.Await(absl::Condition(&first));
   191    }
   192  
   193    // Deliver to the thread group again (other thread still exists).
   194    ASSERT_THAT(kill(getpid(), signo), SyscallSucceeds());
   195  
   196    // Ensure that we can also receive it.
   197    struct signalfd_siginfo rbuf;
   198    ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   199                SyscallSucceedsWithValue(sizeof(rbuf)));
   200    EXPECT_EQ(rbuf.ssi_signo, signo);
   201  
   202    // Mark the test as done.
   203    {
   204      absl::MutexLock ml(&mu);
   205      second = true;
   206    }
   207  
   208    // The other thread should be joinable.
   209    t.Join();
   210  }
   211  
   212  TEST_P(SignalfdTest, Nonblock) {
   213    int signo = GetParam();
   214    // Create the signalfd in non-blocking mode.
   215    sigset_t mask;
   216    sigemptyset(&mask);
   217    sigaddset(&mask, signo);
   218    FileDescriptor fd =
   219        ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_NONBLOCK));
   220  
   221    // We should return if we attempt to read.
   222    struct signalfd_siginfo rbuf;
   223    ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   224                SyscallFailsWithErrno(EWOULDBLOCK));
   225  
   226    // Block and deliver the signal.
   227    const auto scoped_sigmask =
   228        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo));
   229    ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds());
   230  
   231    // Ensure that a read actually works.
   232    ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   233                SyscallSucceedsWithValue(sizeof(rbuf)));
   234    EXPECT_EQ(rbuf.ssi_signo, signo);
   235  
   236    // Should block again.
   237    EXPECT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   238                SyscallFailsWithErrno(EWOULDBLOCK));
   239  }
   240  
   241  TEST_P(SignalfdTest, SetMask) {
   242    int signo = GetParam();
   243    // Create the signalfd matching nothing.
   244    sigset_t mask;
   245    sigemptyset(&mask);
   246    FileDescriptor fd =
   247        ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_NONBLOCK));
   248  
   249    // Block and deliver a signal.
   250    const auto scoped_sigmask =
   251        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo));
   252    ASSERT_THAT(tgkill(getpid(), gettid(), signo), SyscallSucceeds());
   253  
   254    // We should have nothing.
   255    struct signalfd_siginfo rbuf;
   256    ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   257                SyscallFailsWithErrno(EWOULDBLOCK));
   258  
   259    // Change the signal mask.
   260    sigaddset(&mask, signo);
   261    ASSERT_THAT(signalfd(fd.get(), &mask, 0), SyscallSucceeds());
   262  
   263    // We should now have the signal.
   264    ASSERT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   265                SyscallSucceedsWithValue(sizeof(rbuf)));
   266    EXPECT_EQ(rbuf.ssi_signo, signo);
   267  }
   268  
   269  TEST_P(SignalfdTest, Poll) {
   270    int signo = GetParam();
   271    // Create the signalfd.
   272    sigset_t mask;
   273    sigemptyset(&mask);
   274    sigaddset(&mask, signo);
   275    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, 0));
   276  
   277    // Block the signal, and start a thread to deliver it.
   278    const auto scoped_sigmask =
   279        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, signo));
   280    pid_t orig_tid = gettid();
   281    ScopedThread t([&] {
   282      absl::SleepFor(absl::Seconds(5));
   283      ASSERT_THAT(tgkill(getpid(), orig_tid, signo), SyscallSucceeds());
   284    });
   285  
   286    // Start polling for the signal. We expect that it is not available at the
   287    // outset, but then becomes available when the signal is sent. We give a
   288    // timeout of 10000ms (or the delay above + 5 seconds of additional grace
   289    // time).
   290    struct pollfd poll_fd = {fd.get(), POLLIN, 0};
   291    EXPECT_THAT(RetryEINTR(poll)(&poll_fd, 1, 10000),
   292                SyscallSucceedsWithValue(1));
   293  
   294    // Actually read the signal to prevent delivery.
   295    struct signalfd_siginfo rbuf;
   296    EXPECT_THAT(read(fd.get(), &rbuf, sizeof(rbuf)),
   297                SyscallSucceedsWithValue(sizeof(rbuf)));
   298  }
   299  
   300  std::string PrintSigno(::testing::TestParamInfo<int> info) {
   301    switch (info.param) {
   302      case kSigno:
   303        return "kSigno";
   304      case kSignoMax:
   305        return "kSignoMax";
   306      default:
   307        return absl::StrCat(info.param);
   308    }
   309  }
   310  INSTANTIATE_TEST_SUITE_P(Signalfd, SignalfdTest,
   311                           ::testing::Values(kSigno, kSignoMax), PrintSigno);
   312  
   313  TEST(Signalfd, Ppoll) {
   314    sigset_t mask;
   315    sigemptyset(&mask);
   316    sigaddset(&mask, SIGKILL);
   317    FileDescriptor fd =
   318        ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC));
   319  
   320    // Ensure that the given ppoll blocks.
   321    struct pollfd pfd = {};
   322    pfd.fd = fd.get();
   323    pfd.events = POLLIN;
   324    struct timespec timeout = {};
   325    timeout.tv_sec = 1;
   326    EXPECT_THAT(RetryEINTR(ppoll)(&pfd, 1, &timeout, &mask),
   327                SyscallSucceedsWithValue(0));
   328  }
   329  
   330  TEST(Signalfd, KillStillKills) {
   331    sigset_t mask;
   332    sigemptyset(&mask);
   333    sigaddset(&mask, SIGKILL);
   334    FileDescriptor fd =
   335        ASSERT_NO_ERRNO_AND_VALUE(NewSignalFD(&mask, SFD_CLOEXEC));
   336  
   337    // Just because there is a signalfd, we shouldn't see any change in behavior
   338    // for unblockable signals. It's easier to test this with SIGKILL.
   339    const auto scoped_sigmask =
   340        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, SIGKILL));
   341    EXPECT_EXIT(tgkill(getpid(), gettid(), SIGKILL), KilledBySignal(SIGKILL), "");
   342  }
   343  
   344  }  // namespace
   345  
   346  }  // namespace testing
   347  }  // namespace gvisor
   348  
   349  int main(int argc, char** argv) {
   350    // These tests depend on delivering signals. Block them up front so that all
   351    // other threads created by TestInit will also have them blocked, and they
   352    // will not interface with the rest of the test.
   353    sigset_t set;
   354    sigemptyset(&set);
   355    sigaddset(&set, gvisor::testing::kSigno);
   356    sigaddset(&set, gvisor::testing::kSignoMax);
   357    sigaddset(&set, gvisor::testing::kSignoAlt);
   358    TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0);
   359  
   360    gvisor::testing::TestInit(&argc, &argv);
   361  
   362    return gvisor::testing::RunAllTests();
   363  }