270 lines
8.6 KiB
C++
270 lines
8.6 KiB
C++
// 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
|