github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/sigtimedwait.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 <sys/wait.h>
    16  #include <unistd.h>
    17  
    18  #include "gtest/gtest.h"
    19  #include "absl/time/clock.h"
    20  #include "absl/time/time.h"
    21  #include "test/util/file_descriptor.h"
    22  #include "test/util/logging.h"
    23  #include "test/util/signal_util.h"
    24  #include "test/util/test_util.h"
    25  #include "test/util/thread_util.h"
    26  #include "test/util/timer_util.h"
    27  
    28  namespace gvisor {
    29  namespace testing {
    30  
    31  namespace {
    32  
    33  // N.B. main() blocks SIGALRM and SIGCHLD on all threads.
    34  
    35  constexpr int kAlarmSecs = 12;
    36  
    37  void NoopHandler(int sig, siginfo_t* info, void* context) {}
    38  
    39  TEST(SigtimedwaitTest, InvalidTimeout) {
    40    sigset_t mask;
    41    sigemptyset(&mask);
    42    struct timespec timeout = {0, 1000000001};
    43    EXPECT_THAT(sigtimedwait(&mask, nullptr, &timeout),
    44                SyscallFailsWithErrno(EINVAL));
    45    timeout = {-1, 0};
    46    EXPECT_THAT(sigtimedwait(&mask, nullptr, &timeout),
    47                SyscallFailsWithErrno(EINVAL));
    48    timeout = {0, -1};
    49    EXPECT_THAT(sigtimedwait(&mask, nullptr, &timeout),
    50                SyscallFailsWithErrno(EINVAL));
    51  }
    52  
    53  // No random save as the test relies on alarm timing. Cooperative save tests
    54  // already cover the save between alarm and wait.
    55  TEST(SigtimedwaitTest, AlarmReturnsAlarm) {
    56    struct itimerval itv = {};
    57    itv.it_value.tv_sec = kAlarmSecs;
    58    const auto itimer_cleanup =
    59        ASSERT_NO_ERRNO_AND_VALUE(ScopedItimer(ITIMER_REAL, itv));
    60  
    61    sigset_t mask;
    62    sigemptyset(&mask);
    63    sigaddset(&mask, SIGALRM);
    64    siginfo_t info = {};
    65    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, &info, nullptr),
    66                SyscallSucceedsWithValue(SIGALRM));
    67    EXPECT_EQ(SIGALRM, info.si_signo);
    68  }
    69  
    70  // No random save as the test relies on alarm timing. Cooperative save tests
    71  // already cover the save between alarm and wait.
    72  TEST(SigtimedwaitTest, NullTimeoutReturnsEINTR) {
    73    struct sigaction sa;
    74    sa.sa_sigaction = NoopHandler;
    75    sigfillset(&sa.sa_mask);
    76    sa.sa_flags = SA_SIGINFO;
    77    const auto action_cleanup =
    78        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGALRM, sa));
    79  
    80    const auto mask_cleanup =
    81        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGALRM));
    82  
    83    struct itimerval itv = {};
    84    itv.it_value.tv_sec = kAlarmSecs;
    85    const auto itimer_cleanup =
    86        ASSERT_NO_ERRNO_AND_VALUE(ScopedItimer(ITIMER_REAL, itv));
    87  
    88    sigset_t mask;
    89    sigemptyset(&mask);
    90    EXPECT_THAT(sigtimedwait(&mask, nullptr, nullptr),
    91                SyscallFailsWithErrno(EINTR));
    92  }
    93  
    94  TEST(SigtimedwaitTest, LegitTimeoutReturnsEAGAIN) {
    95    sigset_t mask;
    96    sigemptyset(&mask);
    97    struct timespec timeout = {1, 0};  // 1 second
    98    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, nullptr, &timeout),
    99                SyscallFailsWithErrno(EAGAIN));
   100  }
   101  
   102  TEST(SigtimedwaitTest, ZeroTimeoutReturnsEAGAIN) {
   103    sigset_t mask;
   104    sigemptyset(&mask);
   105    struct timespec timeout = {0, 0};  // 0 second
   106    EXPECT_THAT(sigtimedwait(&mask, nullptr, &timeout),
   107                SyscallFailsWithErrno(EAGAIN));
   108  }
   109  
   110  TEST(SigtimedwaitTest, KillGeneratedSIGCHLD) {
   111    EXPECT_THAT(kill(getpid(), SIGCHLD), SyscallSucceeds());
   112  
   113    sigset_t mask;
   114    sigemptyset(&mask);
   115    sigaddset(&mask, SIGCHLD);
   116    struct timespec ts = {5, 0};
   117    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, nullptr, &ts),
   118                SyscallSucceedsWithValue(SIGCHLD));
   119  }
   120  
   121  TEST(SigtimedwaitTest, ChildExitGeneratedSIGCHLD) {
   122    pid_t pid = fork();
   123    if (pid == 0) {
   124      _exit(0);
   125    }
   126    ASSERT_THAT(pid, SyscallSucceeds());
   127  
   128    int status;
   129    EXPECT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   130    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) << status;
   131  
   132    sigset_t mask;
   133    sigemptyset(&mask);
   134    sigaddset(&mask, SIGCHLD);
   135    struct timespec ts = {5, 0};
   136    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, nullptr, &ts),
   137                SyscallSucceedsWithValue(SIGCHLD));
   138  }
   139  
   140  TEST(SigtimedwaitTest, ChildExitGeneratedSIGCHLDWithHandler) {
   141    // Setup handler for SIGCHLD, but don't unblock it.
   142    struct sigaction sa;
   143    sa.sa_sigaction = NoopHandler;
   144    sigfillset(&sa.sa_mask);
   145    sa.sa_flags = SA_SIGINFO;
   146    const auto action_cleanup =
   147        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGCHLD, sa));
   148  
   149    pid_t pid = fork();
   150    if (pid == 0) {
   151      _exit(0);
   152    }
   153    ASSERT_THAT(pid, SyscallSucceeds());
   154  
   155    sigset_t mask;
   156    sigemptyset(&mask);
   157    sigaddset(&mask, SIGCHLD);
   158    struct timespec ts = {5, 0};
   159    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, nullptr, &ts),
   160                SyscallSucceedsWithValue(SIGCHLD));
   161  
   162    int status;
   163    EXPECT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   164    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0) << status;
   165  }
   166  
   167  // sigtimedwait cannot catch SIGKILL.
   168  TEST(SigtimedwaitTest, SIGKILLUncaught) {
   169    // This is a regression test for sigtimedwait dequeuing SIGKILLs, thus
   170    // preventing the task from exiting.
   171    //
   172    // The explanation below is specific to behavior in gVisor. The Linux behavior
   173    // here is irrelevant because without a bug that prevents delivery of SIGKILL,
   174    // none of this behavior is visible (in Linux or gVisor).
   175    //
   176    // SIGKILL is rather intrusive. Simply sending the SIGKILL marks
   177    // ThreadGroup.exitStatus as exiting with SIGKILL, before the SIGKILL is even
   178    // delivered.
   179    //
   180    // As a result, we cannot simply exit the child with a different exit code if
   181    // it survives and expect to see that code in waitpid because:
   182    //   1. PrepareGroupExit will override Task.exitStatus with
   183    //      ThreadGroup.exitStatus.
   184    //   2. waitpid(2) will always return ThreadGroup.exitStatus rather than
   185    //      Task.exitStatus.
   186    //
   187    // We could use exit(2) to set Task.exitStatus without override, and a SIGCHLD
   188    // handler to receive Task.exitStatus in the parent, but with that much
   189    // test complexity, it is cleaner to simply use a pipe to notify the parent
   190    // that we survived.
   191    constexpr auto kSigtimedwaitSetupTime = absl::Seconds(2);
   192  
   193    int pipe_fds[2];
   194    ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds());
   195    FileDescriptor rfd(pipe_fds[0]);
   196    FileDescriptor wfd(pipe_fds[1]);
   197  
   198    pid_t pid = fork();
   199    if (pid == 0) {
   200      rfd.reset();
   201  
   202      sigset_t mask;
   203      sigemptyset(&mask);
   204      sigaddset(&mask, SIGKILL);
   205      RetryEINTR(sigtimedwait)(&mask, nullptr, nullptr);
   206  
   207      // Survived.
   208      char c = 'a';
   209      TEST_PCHECK(WriteFd(wfd.get(), &c, 1) == 1);
   210      _exit(1);
   211    }
   212    ASSERT_THAT(pid, SyscallSucceeds());
   213  
   214    wfd.reset();
   215  
   216    // Wait for child to block in sigtimedwait, then kill it.
   217    absl::SleepFor(kSigtimedwaitSetupTime);
   218  
   219    // Sending SIGKILL will attempt to enqueue the signal twice: once in the
   220    // normal signal sending path, and once to all Tasks in the ThreadGroup when
   221    // applying SIGKILL side-effects.
   222    //
   223    // If we use kill(2), the former will be on the ThreadGroup signal queue and
   224    // the latter will be on the Task signal queue. sigtimedwait can only dequeue
   225    // one signal, so the other would kill the Task, masking bugs.
   226    //
   227    // If we use tkill(2), the former will be on the Task signal queue and the
   228    // latter will be dropped as a duplicate. Then sigtimedwait can theoretically
   229    // dequeue the single SIGKILL.
   230    EXPECT_THAT(syscall(SYS_tkill, pid, SIGKILL), SyscallSucceeds());
   231  
   232    int status;
   233    EXPECT_THAT(RetryEINTR(waitpid)(pid, &status, 0),
   234                SyscallSucceedsWithValue(pid));
   235    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) << status;
   236  
   237    // Child shouldn't have survived.
   238    char c;
   239    EXPECT_THAT(ReadFd(rfd.get(), &c, 1), SyscallSucceedsWithValue(0));
   240  }
   241  
   242  TEST(SigtimedwaitTest, IgnoredUnmaskedSignal) {
   243    constexpr int kSigno = SIGUSR1;
   244    constexpr auto kSigtimedwaitSetupTime = absl::Seconds(2);
   245    constexpr auto kSigtimedwaitTimeout = absl::Seconds(5);
   246    ASSERT_GT(kSigtimedwaitTimeout, kSigtimedwaitSetupTime);
   247  
   248    // Ensure that kSigno is ignored, and unmasked on this thread.
   249    struct sigaction sa = {};
   250    sa.sa_handler = SIG_IGN;
   251    const auto scoped_sigaction =
   252        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(kSigno, sa));
   253    sigset_t mask;
   254    sigemptyset(&mask);
   255    sigaddset(&mask, kSigno);
   256    auto scoped_sigmask =
   257        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, mask));
   258  
   259    // Create a thread which will send us kSigno while we are blocked in
   260    // sigtimedwait.
   261    pid_t tid = gettid();
   262    ScopedThread sigthread([&] {
   263      absl::SleepFor(kSigtimedwaitSetupTime);
   264      EXPECT_THAT(tgkill(getpid(), tid, kSigno), SyscallSucceeds());
   265    });
   266  
   267    // sigtimedwait should not observe kSigno since it is ignored and already
   268    // unmasked, causing it to be dropped before it is enqueued.
   269    struct timespec timeout_ts = absl::ToTimespec(kSigtimedwaitTimeout);
   270    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, nullptr, &timeout_ts),
   271                SyscallFailsWithErrno(EAGAIN));
   272  }
   273  
   274  TEST(SigtimedwaitTest, IgnoredMaskedSignal) {
   275    constexpr int kSigno = SIGUSR1;
   276    constexpr auto kSigtimedwaitSetupTime = absl::Seconds(2);
   277    constexpr auto kSigtimedwaitTimeout = absl::Seconds(5);
   278    ASSERT_GT(kSigtimedwaitTimeout, kSigtimedwaitSetupTime);
   279  
   280    // Ensure that kSigno is ignored, and masked on this thread.
   281    struct sigaction sa = {};
   282    sa.sa_handler = SIG_IGN;
   283    const auto scoped_sigaction =
   284        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(kSigno, sa));
   285    sigset_t mask;
   286    sigemptyset(&mask);
   287    sigaddset(&mask, kSigno);
   288    auto scoped_sigmask =
   289        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_BLOCK, mask));
   290  
   291    // Create a thread which will send us kSigno while we are blocked in
   292    // sigtimedwait.
   293    pid_t tid = gettid();
   294    ScopedThread sigthread([&] {
   295      absl::SleepFor(kSigtimedwaitSetupTime);
   296      EXPECT_THAT(tgkill(getpid(), tid, kSigno), SyscallSucceeds());
   297    });
   298  
   299    // sigtimedwait should observe kSigno since it is normally masked, causing it
   300    // to be enqueued despite being ignored.
   301    struct timespec timeout_ts = absl::ToTimespec(kSigtimedwaitTimeout);
   302    EXPECT_THAT(RetryEINTR(sigtimedwait)(&mask, nullptr, &timeout_ts),
   303                SyscallSucceedsWithValue(kSigno));
   304  }
   305  
   306  }  // namespace
   307  
   308  }  // namespace testing
   309  }  // namespace gvisor
   310  
   311  int main(int argc, char** argv) {
   312    // These tests depend on delivering SIGALRM/SIGCHLD to the main thread or in
   313    // sigtimedwait. Block them so that any other threads created by TestInit will
   314    // also have them blocked.
   315    sigset_t set;
   316    sigemptyset(&set);
   317    sigaddset(&set, SIGALRM);
   318    sigaddset(&set, SIGCHLD);
   319    TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0);
   320  
   321    gvisor::testing::TestInit(&argc, &argv);
   322    return gvisor::testing::RunAllTests();
   323  }