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 }