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