github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/sigaltstack.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 <errno.h>
    16  #include <signal.h>
    17  #include <stdio.h>
    18  #include <string.h>
    19  #include <unistd.h>
    20  
    21  #include <functional>
    22  #include <vector>
    23  
    24  #include "gtest/gtest.h"
    25  #include "test/util/cleanup.h"
    26  #include "test/util/fs_util.h"
    27  #include "test/util/multiprocess_util.h"
    28  #include "test/util/posix_error.h"
    29  #include "test/util/signal_util.h"
    30  #include "test/util/test_util.h"
    31  #include "test/util/thread_util.h"
    32  
    33  namespace gvisor {
    34  namespace testing {
    35  
    36  namespace {
    37  
    38  PosixErrorOr<Cleanup> ScopedSigaltstack(stack_t const& stack) {
    39    stack_t old_stack;
    40    int rc = sigaltstack(&stack, &old_stack);
    41    MaybeSave();
    42    if (rc < 0) {
    43      return PosixError(errno, "sigaltstack failed");
    44    }
    45    return Cleanup([old_stack] {
    46      EXPECT_THAT(sigaltstack(&old_stack, nullptr), SyscallSucceeds());
    47    });
    48  }
    49  
    50  volatile bool got_signal = false;
    51  volatile int sigaltstack_errno = 0;
    52  volatile int ss_flags = 0;
    53  
    54  void sigaltstack_handler(int sig, siginfo_t* siginfo, void* arg) {
    55    got_signal = true;
    56  
    57    stack_t stack;
    58    int ret = sigaltstack(nullptr, &stack);
    59    MaybeSave();
    60    if (ret < 0) {
    61      sigaltstack_errno = errno;
    62      return;
    63    }
    64    ss_flags = stack.ss_flags;
    65  }
    66  
    67  TEST(SigaltstackTest, Success) {
    68    std::vector<char> stack_mem(SIGSTKSZ);
    69    stack_t stack = {};
    70    stack.ss_sp = stack_mem.data();
    71    stack.ss_size = stack_mem.size();
    72    auto const cleanup_sigstack =
    73        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaltstack(stack));
    74  
    75    struct sigaction sa = {};
    76    sa.sa_sigaction = sigaltstack_handler;
    77    sigfillset(&sa.sa_mask);
    78    sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
    79    auto const cleanup_sa =
    80        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGUSR1, sa));
    81  
    82    // Send signal to this thread, as sigaltstack is per-thread.
    83    EXPECT_THAT(tgkill(getpid(), gettid(), SIGUSR1), SyscallSucceeds());
    84  
    85    EXPECT_TRUE(got_signal);
    86    EXPECT_EQ(sigaltstack_errno, 0);
    87    EXPECT_NE(0, ss_flags & SS_ONSTACK);
    88  }
    89  
    90  TEST(SigaltstackTest, ResetByExecve) {
    91    std::vector<char> stack_mem(SIGSTKSZ);
    92    stack_t stack = {};
    93    stack.ss_sp = stack_mem.data();
    94    stack.ss_size = stack_mem.size();
    95    auto const cleanup_sigstack =
    96        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaltstack(stack));
    97  
    98    std::string full_path = RunfilePath("test/syscalls/linux/sigaltstack_check");
    99  
   100    pid_t child_pid = -1;
   101    int execve_errno = 0;
   102    auto cleanup = ASSERT_NO_ERRNO_AND_VALUE(
   103        ForkAndExec(full_path, {"sigaltstack_check"}, {}, nullptr, &child_pid,
   104                    &execve_errno));
   105  
   106    ASSERT_GT(child_pid, 0);
   107    ASSERT_EQ(execve_errno, 0);
   108  
   109    int status = 0;
   110    ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), SyscallSucceeds());
   111    ASSERT_TRUE(WIFEXITED(status));
   112    ASSERT_EQ(WEXITSTATUS(status), 0);
   113  }
   114  
   115  volatile bool badhandler_on_sigaltstack = true;      // Set by the handler.
   116  char* volatile badhandler_low_water_mark = nullptr;  // Set by the handler.
   117  volatile uint8_t badhandler_recursive_faults = 0;    // Consumed by the handler.
   118  
   119  void badhandler(int sig, siginfo_t* siginfo, void* arg) {
   120    char stack_var = 0;
   121    char* current_ss = &stack_var;
   122  
   123    stack_t stack;
   124    int ret = sigaltstack(nullptr, &stack);
   125    if (ret < 0 || (stack.ss_flags & SS_ONSTACK) != SS_ONSTACK) {
   126      // We should always be marked as being on the stack. Don't allow this to hit
   127      // the bottom if this is ever not true (the main test will fail as a
   128      // result, but we still need to unwind the recursive faults).
   129      badhandler_on_sigaltstack = false;
   130    }
   131    if (current_ss < badhandler_low_water_mark) {
   132      // Record the low point for the signal stack. We never expected this to be
   133      // before stack bottom, but this is asserted in the actual test.
   134      badhandler_low_water_mark = current_ss;
   135    }
   136    if (badhandler_recursive_faults > 0) {
   137      badhandler_recursive_faults--;
   138      Fault();
   139    }
   140    FixupFault(reinterpret_cast<ucontext_t*>(arg));
   141  }
   142  
   143  TEST(SigaltstackTest, WalksOffBottom) {
   144    // This test marks the upper half of the stack_mem array as the signal stack.
   145    // It asserts that when a fault occurs in the handler (already on the signal
   146    // stack), we eventually continue to fault our way off the stack. We should
   147    // not revert to the top of the signal stack when we fall off the bottom and
   148    // the signal stack should remain "in use". When we fall off the signal stack,
   149    // we should have an unconditional signal delivered and not start using the
   150    // first part of the stack_mem array.
   151    std::vector<char> stack_mem(SIGSTKSZ * 2);
   152    stack_t stack = {};
   153    stack.ss_sp = stack_mem.data() + SIGSTKSZ;  // See above: upper half.
   154    stack.ss_size = SIGSTKSZ;                   // Only one half the array.
   155    auto const cleanup_sigstack =
   156        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaltstack(stack));
   157  
   158    // Setup the handler: this must be for SIGSEGV, and it must allow proper
   159    // nesting (no signal mask, no defer) so that we can trigger multiple times.
   160    //
   161    // When we walk off the bottom of the signal stack and force signal delivery
   162    // of a SIGSEGV, the handler will revert to the default behavior (kill).
   163    struct sigaction sa = {};
   164    sa.sa_sigaction = badhandler;
   165    sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
   166    auto const cleanup_sa =
   167        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGSEGV, sa));
   168  
   169    // Trigger a single fault.
   170    badhandler_low_water_mark =
   171        static_cast<char*>(stack.ss_sp) + SIGSTKSZ;  // Expected top.
   172    badhandler_recursive_faults = 0;                 // Disable refault.
   173    Fault();
   174    EXPECT_TRUE(badhandler_on_sigaltstack);
   175    EXPECT_THAT(sigaltstack(nullptr, &stack), SyscallSucceeds());
   176    EXPECT_EQ(stack.ss_flags & SS_ONSTACK, 0);
   177    EXPECT_LT(badhandler_low_water_mark,
   178              reinterpret_cast<char*>(stack.ss_sp) + 2 * SIGSTKSZ);
   179    EXPECT_GT(badhandler_low_water_mark, reinterpret_cast<char*>(stack.ss_sp));
   180  
   181    // Trigger two faults.
   182    char* prev_low_water_mark = badhandler_low_water_mark;  // Previous top.
   183    badhandler_recursive_faults = 1;                        // One refault.
   184    Fault();
   185    ASSERT_TRUE(badhandler_on_sigaltstack);
   186    EXPECT_THAT(sigaltstack(nullptr, &stack), SyscallSucceeds());
   187    EXPECT_EQ(stack.ss_flags & SS_ONSTACK, 0);
   188    EXPECT_LT(badhandler_low_water_mark, prev_low_water_mark);
   189    EXPECT_GT(badhandler_low_water_mark, reinterpret_cast<char*>(stack.ss_sp));
   190  
   191    // Calculate the stack growth for a fault, and set the recursive faults to
   192    // ensure that the signal handler stack required exceeds our marked stack area
   193    // by a minimal amount. It should remain in the valid stack_mem area so that
   194    // we can test the signal is forced merely by going out of the signal stack
   195    // bounds, not by a genuine fault.
   196    uintptr_t frame_size =
   197        static_cast<uintptr_t>(prev_low_water_mark - badhandler_low_water_mark);
   198    badhandler_recursive_faults = (SIGSTKSZ + frame_size) / frame_size;
   199    EXPECT_EXIT(Fault(), ::testing::KilledBySignal(SIGSEGV), "");
   200  }
   201  
   202  volatile int setonstack_retval = 0;  // Set by the handler.
   203  volatile int setonstack_errno = 0;   // Set by the handler.
   204  
   205  void setonstack(int sig, siginfo_t* siginfo, void* arg) {
   206    char stack_mem[SIGSTKSZ];
   207    stack_t stack = {};
   208    stack.ss_sp = &stack_mem[0];
   209    stack.ss_size = SIGSTKSZ;
   210    setonstack_retval = sigaltstack(&stack, nullptr);
   211    setonstack_errno = errno;
   212    FixupFault(reinterpret_cast<ucontext_t*>(arg));
   213  }
   214  
   215  TEST(SigaltstackTest, SetWhileOnStack) {
   216    // Reserve twice as much stack here, since the handler will allocate a vector
   217    // of size SIGTKSZ and attempt to set the sigaltstack to that value.
   218    std::vector<char> stack_mem(2 * SIGSTKSZ);
   219    stack_t stack = {};
   220    stack.ss_sp = stack_mem.data();
   221    stack.ss_size = stack_mem.size();
   222    auto const cleanup_sigstack =
   223        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaltstack(stack));
   224  
   225    // See above.
   226    struct sigaction sa = {};
   227    sa.sa_sigaction = setonstack;
   228    sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
   229    auto const cleanup_sa =
   230        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGSEGV, sa));
   231  
   232    // Trigger a fault.
   233    Fault();
   234  
   235    // The set should have failed.
   236    EXPECT_EQ(setonstack_retval, -1);
   237    EXPECT_EQ(setonstack_errno, EPERM);
   238  }
   239  
   240  TEST(SigaltstackTest, SetCurrentStack) {
   241    // This is executed as an exit test because once the signal stack is set to
   242    // the local stack, there's no good way to unwind. We don't want to taint the
   243    // test of any other tests that might run within this process.
   244    EXPECT_EXIT(
   245        {
   246          char stack_value = 0;
   247          stack_t stack = {};
   248          stack.ss_sp = &stack_value - kPageSize;  // Lower than current level.
   249          stack.ss_size = 2 * kPageSize;  // => &stack_value +/- kPageSize.
   250          TEST_CHECK(sigaltstack(&stack, nullptr) == 0);
   251          TEST_CHECK(sigaltstack(nullptr, &stack) == 0);
   252          TEST_CHECK((stack.ss_flags & SS_ONSTACK) != 0);
   253  
   254          // Should not be able to change the stack (even no-op).
   255          TEST_CHECK(sigaltstack(&stack, nullptr) == -1 && errno == EPERM);
   256  
   257          // Should not be able to disable the stack.
   258          stack.ss_flags = SS_DISABLE;
   259          TEST_CHECK(sigaltstack(&stack, nullptr) == -1 && errno == EPERM);
   260          exit(0);
   261        },
   262        ::testing::ExitedWithCode(0), "");
   263  }
   264  
   265  }  // namespace
   266  
   267  }  // namespace testing
   268  }  // namespace gvisor