gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/rtsignal.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/syscall.h>
    16  #include <sys/types.h>
    17  #include <unistd.h>
    18  
    19  #include <cerrno>
    20  #include <csignal>
    21  
    22  #include "gtest/gtest.h"
    23  #include "test/util/cleanup.h"
    24  #include "test/util/logging.h"
    25  #include "test/util/posix_error.h"
    26  #include "test/util/signal_util.h"
    27  #include "test/util/test_util.h"
    28  
    29  namespace gvisor {
    30  namespace testing {
    31  
    32  namespace {
    33  
    34  // saved_info is set by the handler.
    35  siginfo_t saved_info;
    36  
    37  // has_saved_info is set to true by the handler.
    38  volatile bool has_saved_info;
    39  
    40  void SigHandler(int sig, siginfo_t* info, void* context) {
    41    // Copy to the given info.
    42    saved_info = *info;
    43    has_saved_info = true;
    44  }
    45  
    46  void ClearSavedInfo() {
    47    // Clear the cached info.
    48    memset(&saved_info, 0, sizeof(saved_info));
    49    has_saved_info = false;
    50  }
    51  
    52  PosixErrorOr<Cleanup> SetupSignalHandler(int sig) {
    53    struct sigaction sa;
    54    sa.sa_sigaction = SigHandler;
    55    sigfillset(&sa.sa_mask);
    56    sa.sa_flags = SA_SIGINFO;
    57    return ScopedSigaction(sig, sa);
    58  }
    59  
    60  class RtSignalTest : public ::testing::Test {
    61   protected:
    62    void SetUp() override {
    63      action_cleanup_ = ASSERT_NO_ERRNO_AND_VALUE(SetupSignalHandler(SIGUSR1));
    64      mask_cleanup_ =
    65          ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGUSR1));
    66    }
    67  
    68    void TearDown() override { ClearSavedInfo(); }
    69  
    70   private:
    71    Cleanup action_cleanup_;
    72    Cleanup mask_cleanup_;
    73  };
    74  
    75  static int rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t* uinfo) {
    76    int ret;
    77    do {
    78      // NOTE(b/25434735): rt_sigqueueinfo(2) could return EAGAIN for RT signals.
    79      ret = syscall(SYS_rt_sigqueueinfo, tgid, sig, uinfo);
    80    } while (ret == -1 && errno == EAGAIN);
    81    return ret;
    82  }
    83  
    84  TEST_F(RtSignalTest, InvalidTID) {
    85    siginfo_t uinfo;
    86    // Depending on the kernel version, these calls may fail with
    87    // ESRCH (goobunutu machines) or EPERM (production machines). Thus,
    88    // the test simply ensures that they do fail.
    89    EXPECT_THAT(rt_sigqueueinfo(-1, SIGUSR1, &uinfo), SyscallFails());
    90    EXPECT_FALSE(has_saved_info);
    91    EXPECT_THAT(rt_sigqueueinfo(0, SIGUSR1, &uinfo), SyscallFails());
    92    EXPECT_FALSE(has_saved_info);
    93  }
    94  
    95  TEST_F(RtSignalTest, InvalidCodes) {
    96    siginfo_t uinfo;
    97  
    98    // We need a child for the code checks to apply. If the process is delivering
    99    // to itself, then it can use whatever codes it wants and they will go
   100    // through.
   101    pid_t child = fork();
   102    if (child == 0) {
   103      _exit(1);
   104    }
   105    ASSERT_THAT(child, SyscallSucceeds());
   106  
   107    // These are not allowed for child processes.
   108    uinfo.si_code = 0;  // SI_USER.
   109    EXPECT_THAT(rt_sigqueueinfo(child, SIGUSR1, &uinfo),
   110                SyscallFailsWithErrno(EPERM));
   111    uinfo.si_code = 0x80;  // SI_KERNEL.
   112    EXPECT_THAT(rt_sigqueueinfo(child, SIGUSR1, &uinfo),
   113                SyscallFailsWithErrno(EPERM));
   114    uinfo.si_code = -6;  // SI_TKILL.
   115    EXPECT_THAT(rt_sigqueueinfo(child, SIGUSR1, &uinfo),
   116                SyscallFailsWithErrno(EPERM));
   117    uinfo.si_code = -1;  // SI_QUEUE (allowed).
   118    EXPECT_THAT(rt_sigqueueinfo(child, SIGUSR1, &uinfo), SyscallSucceeds());
   119  
   120    // Join the child process.
   121    EXPECT_THAT(waitpid(child, nullptr, 0), SyscallSucceeds());
   122  }
   123  
   124  TEST_F(RtSignalTest, ValueDelivered) {
   125    siginfo_t uinfo;
   126    uinfo.si_code = -1;  // SI_QUEUE (allowed).
   127    uinfo.si_errno = 0x1234;
   128  
   129    EXPECT_EQ(saved_info.si_errno, 0x0);
   130    EXPECT_THAT(rt_sigqueueinfo(getpid(), SIGUSR1, &uinfo), SyscallSucceeds());
   131    EXPECT_TRUE(has_saved_info);
   132    EXPECT_EQ(saved_info.si_errno, 0x1234);
   133  }
   134  
   135  TEST_F(RtSignalTest, SignoMatch) {
   136    auto action2_cleanup = ASSERT_NO_ERRNO_AND_VALUE(SetupSignalHandler(SIGUSR2));
   137    auto mask2_cleanup =
   138        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGUSR2));
   139  
   140    siginfo_t uinfo;
   141    uinfo.si_code = -1;  // SI_QUEUE (allowed).
   142  
   143    EXPECT_THAT(rt_sigqueueinfo(getpid(), SIGUSR1, &uinfo), SyscallSucceeds());
   144    EXPECT_TRUE(has_saved_info);
   145    EXPECT_EQ(saved_info.si_signo, SIGUSR1);
   146  
   147    ClearSavedInfo();
   148  
   149    EXPECT_THAT(rt_sigqueueinfo(getpid(), SIGUSR2, &uinfo), SyscallSucceeds());
   150    EXPECT_TRUE(has_saved_info);
   151    EXPECT_EQ(saved_info.si_signo, SIGUSR2);
   152  }
   153  
   154  }  // namespace
   155  
   156  }  // namespace testing
   157  }  // namespace gvisor
   158  
   159  int main(int argc, char** argv) {
   160    // These tests depend on delivering SIGUSR1/2 to the main thread (so they can
   161    // synchronously check has_saved_info). Block these so that any other threads
   162    // created by TestInit will also have them blocked.
   163    sigset_t set;
   164    sigemptyset(&set);
   165    sigaddset(&set, SIGUSR1);
   166    sigaddset(&set, SIGUSR2);
   167    TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0);
   168  
   169    gvisor::testing::TestInit(&argc, &argv);
   170    return gvisor::testing::RunAllTests();
   171  }