diff options
Diffstat (limited to 'test/syscalls/linux/sigprocmask.cc')
-rw-r--r-- | test/syscalls/linux/sigprocmask.cc | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/test/syscalls/linux/sigprocmask.cc b/test/syscalls/linux/sigprocmask.cc new file mode 100644 index 000000000..a603fc1d1 --- /dev/null +++ b/test/syscalls/linux/sigprocmask.cc @@ -0,0 +1,269 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <signal.h> +#include <stddef.h> +#include <sys/syscall.h> +#include <unistd.h> + +#include "gtest/gtest.h" +#include "test/util/signal_util.h" +#include "test/util/test_util.h" + +namespace gvisor { +namespace testing { + +namespace { + +// Signals numbers used for testing. +static constexpr int kTestSignal1 = SIGUSR1; +static constexpr int kTestSignal2 = SIGUSR2; + +static int raw_sigprocmask(int how, const sigset_t* set, sigset_t* oldset) { + return syscall(SYS_rt_sigprocmask, how, set, oldset, _NSIG / 8); +} + +// count of the number of signals received +int signal_count[kMaxSignal + 1]; + +// signal handler increments the signal counter +void SigHandler(int sig, siginfo_t* info, void* context) { + TEST_CHECK(sig > 0 && sig <= kMaxSignal); + signal_count[sig] += 1; +} + +// The test fixture saves and restores the signal mask and +// sets up handlers for kTestSignal1 and kTestSignal2. +class SigProcMaskTest : public ::testing::Test { + protected: + void SetUp() override { + // Save the current signal mask. + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &mask_), + SyscallSucceeds()); + + // Setup signal handlers for kTestSignal1 and kTestSignal2. + struct sigaction sa; + sa.sa_sigaction = SigHandler; + sigfillset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + EXPECT_THAT(sigaction(kTestSignal1, &sa, &sa_test_sig_1_), + SyscallSucceeds()); + EXPECT_THAT(sigaction(kTestSignal2, &sa, &sa_test_sig_2_), + SyscallSucceeds()); + + // Clear the signal counters. + memset(signal_count, 0, sizeof(signal_count)); + } + + void TearDown() override { + // Restore the signal mask. + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, &mask_, nullptr), + SyscallSucceeds()); + + // Restore the signal handlers for kTestSignal1 and kTestSignal2. + EXPECT_THAT(sigaction(kTestSignal1, &sa_test_sig_1_, nullptr), + SyscallSucceeds()); + EXPECT_THAT(sigaction(kTestSignal2, &sa_test_sig_2_, nullptr), + SyscallSucceeds()); + } + + private: + sigset_t mask_; + struct sigaction sa_test_sig_1_; + struct sigaction sa_test_sig_2_; +}; + +// Both sigsets nullptr should succeed and do nothing. +TEST_F(SigProcMaskTest, NullAddress) { + EXPECT_THAT(raw_sigprocmask(SIG_BLOCK, nullptr, NULL), SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_UNBLOCK, nullptr, NULL), SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, NULL), SyscallSucceeds()); +} + +// Bad address for either sigset should fail with EFAULT. +TEST_F(SigProcMaskTest, BadAddress) { + sigset_t* bad_addr = reinterpret_cast<sigset_t*>(-1); + + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, bad_addr, nullptr), + SyscallFailsWithErrno(EFAULT)); + + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, bad_addr), + SyscallFailsWithErrno(EFAULT)); +} + +// Bad value of the "how" parameter should fail with EINVAL. +TEST_F(SigProcMaskTest, BadParameter) { + int bad_param_1 = -1; + int bad_param_2 = 42; + + sigset_t set1; + sigemptyset(&set1); + + EXPECT_THAT(raw_sigprocmask(bad_param_1, &set1, nullptr), + SyscallFailsWithErrno(EINVAL)); + + EXPECT_THAT(raw_sigprocmask(bad_param_2, &set1, nullptr), + SyscallFailsWithErrno(EINVAL)); +} + +// Check that we can get the current signal mask. +TEST_F(SigProcMaskTest, GetMask) { + sigset_t set1; + sigset_t set2; + + sigemptyset(&set1); + sigfillset(&set2); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &set1), SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &set2), SyscallSucceeds()); + EXPECT_THAT(set1, EqualsSigset(set2)); +} + +// Check that we can set the signal mask. +TEST_F(SigProcMaskTest, SetMask) { + sigset_t actual; + sigset_t expected; + + // Try to mask all signals + sigfillset(&expected); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, &expected, nullptr), + SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &actual), + SyscallSucceeds()); + // sigprocmask() should have silently ignored SIGKILL and SIGSTOP. + sigdelset(&expected, SIGSTOP); + sigdelset(&expected, SIGKILL); + EXPECT_THAT(actual, EqualsSigset(expected)); + + // Try to clear the signal mask + sigemptyset(&expected); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, &expected, nullptr), + SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &actual), + SyscallSucceeds()); + EXPECT_THAT(actual, EqualsSigset(expected)); + + // Try to set a mask with one signal. + sigemptyset(&expected); + sigaddset(&expected, kTestSignal1); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, &expected, nullptr), + SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &actual), + SyscallSucceeds()); + EXPECT_THAT(actual, EqualsSigset(expected)); +} + +// Check that we can add and remove signals. +TEST_F(SigProcMaskTest, BlockUnblock) { + sigset_t actual; + sigset_t expected; + + // Try to set a mask with one signal. + sigemptyset(&expected); + sigaddset(&expected, kTestSignal1); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, &expected, nullptr), + SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &actual), + SyscallSucceeds()); + EXPECT_THAT(actual, EqualsSigset(expected)); + + // Try to add another signal. + sigset_t block; + sigemptyset(&block); + sigaddset(&block, kTestSignal2); + EXPECT_THAT(raw_sigprocmask(SIG_BLOCK, &block, nullptr), SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &actual), + SyscallSucceeds()); + sigaddset(&expected, kTestSignal2); + EXPECT_THAT(actual, EqualsSigset(expected)); + + // Try to remove a signal. + sigset_t unblock; + sigemptyset(&unblock); + sigaddset(&unblock, kTestSignal1); + EXPECT_THAT(raw_sigprocmask(SIG_UNBLOCK, &unblock, nullptr), + SyscallSucceeds()); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, nullptr, &actual), + SyscallSucceeds()); + sigdelset(&expected, kTestSignal1); + EXPECT_THAT(actual, EqualsSigset(expected)); +} + +// Test that the signal mask actually blocks signals. +TEST_F(SigProcMaskTest, SignalHandler) { + sigset_t mask; + + // clear the signal mask + sigemptyset(&mask); + EXPECT_THAT(raw_sigprocmask(SIG_SETMASK, &mask, nullptr), SyscallSucceeds()); + + // Check the initial signal counts. + EXPECT_EQ(0, signal_count[kTestSignal1]); + EXPECT_EQ(0, signal_count[kTestSignal2]); + + // Check that both kTestSignal1 and kTestSignal2 are not blocked. + raise(kTestSignal1); + raise(kTestSignal2); + EXPECT_EQ(1, signal_count[kTestSignal1]); + EXPECT_EQ(1, signal_count[kTestSignal2]); + + // Block kTestSignal1. + sigaddset(&mask, kTestSignal1); + EXPECT_THAT(raw_sigprocmask(SIG_BLOCK, &mask, nullptr), SyscallSucceeds()); + + // Check that kTestSignal1 is blocked. + raise(kTestSignal1); + raise(kTestSignal2); + EXPECT_EQ(1, signal_count[kTestSignal1]); + EXPECT_EQ(2, signal_count[kTestSignal2]); + + // Unblock kTestSignal1. + sigaddset(&mask, kTestSignal1); + EXPECT_THAT(raw_sigprocmask(SIG_UNBLOCK, &mask, nullptr), SyscallSucceeds()); + + // Check that the unblocked kTestSignal1 has been delivered. + EXPECT_EQ(2, signal_count[kTestSignal1]); + EXPECT_EQ(2, signal_count[kTestSignal2]); +} + +// Check that sigprocmask correctly handles aliasing of the set and oldset +// pointers. Regression test for b/30502311. +TEST_F(SigProcMaskTest, AliasedSets) { + sigset_t mask; + + // Set a mask in which only kTestSignal1 is blocked. + sigset_t mask1; + sigemptyset(&mask1); + sigaddset(&mask1, kTestSignal1); + mask = mask1; + ASSERT_THAT(raw_sigprocmask(SIG_SETMASK, &mask, nullptr), SyscallSucceeds()); + + // Exchange it with a mask in which only kTestSignal2 is blocked. + sigset_t mask2; + sigemptyset(&mask2); + sigaddset(&mask2, kTestSignal2); + mask = mask2; + ASSERT_THAT(raw_sigprocmask(SIG_SETMASK, &mask, &mask), SyscallSucceeds()); + + // Check that the exchange succeeeded: + // mask should now contain the previously-set mask blocking only kTestSignal1. + EXPECT_THAT(mask, EqualsSigset(mask1)); + // The current mask should block only kTestSignal2. + ASSERT_THAT(raw_sigprocmask(0, nullptr, &mask), SyscallSucceeds()); + EXPECT_THAT(mask, EqualsSigset(mask2)); +} + +} // namespace + +} // namespace testing +} // namespace gvisor |