gvisor/test/syscalls/linux/sigprocmask.cc

273 lines
8.7 KiB
C++

// Copyright 2018 Google LLC
//
// 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.
// TODO: gvisor currently drops masked signals on the floor.
if (!IsRunningOnGvisor()) {
EXPECT_EQ(2, signal_count[kTestSignal1]);
}
EXPECT_EQ(2, signal_count[kTestSignal2]);
}
// Check that sigprocmask correctly handles aliasing of the set and oldset
// pointers.
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