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 }