github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/sigreturn_amd64.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 <signal.h>
    16  #include <sys/types.h>
    17  #include <sys/ucontext.h>
    18  #include <unistd.h>
    19  
    20  #include "gtest/gtest.h"
    21  #include "test/util/logging.h"
    22  #include "test/util/signal_util.h"
    23  #include "test/util/test_util.h"
    24  #include "test/util/timer_util.h"
    25  
    26  namespace gvisor {
    27  namespace testing {
    28  
    29  namespace {
    30  
    31  constexpr uint64_t kOrigRcx = 0xdeadbeeffacefeed;
    32  constexpr uint64_t kOrigR11 = 0xfacefeedbaad1dea;
    33  
    34  volatile int gotvtalrm, ready;
    35  
    36  void sigvtalrm(int sig, siginfo_t* siginfo, void* _uc) {
    37    ucontext_t* uc = reinterpret_cast<ucontext_t*>(_uc);
    38  
    39    // Verify that:
    40    // - test is in the busy-wait loop waiting for signal.
    41    // - %rcx and %r11 values in mcontext_t match kOrigRcx and kOrigR11.
    42    if (ready &&
    43        static_cast<uint64_t>(uc->uc_mcontext.gregs[REG_RCX]) == kOrigRcx &&
    44        static_cast<uint64_t>(uc->uc_mcontext.gregs[REG_R11]) == kOrigR11) {
    45      // Modify the values %rcx and %r11 in the ucontext. These are the
    46      // values seen by the application after the signal handler returns.
    47      uc->uc_mcontext.gregs[REG_RCX] = ~kOrigRcx;
    48      uc->uc_mcontext.gregs[REG_R11] = ~kOrigR11;
    49      gotvtalrm = 1;
    50    }
    51  }
    52  
    53  TEST(SigIretTest, CheckRcxR11) {
    54    // Setup signal handler for SIGVTALRM.
    55    struct sigaction sa = {};
    56    sigfillset(&sa.sa_mask);
    57    sa.sa_sigaction = sigvtalrm;
    58    sa.sa_flags = SA_SIGINFO;
    59    auto const action_cleanup =
    60        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGVTALRM, sa));
    61  
    62    auto const mask_cleanup =
    63        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGVTALRM));
    64  
    65    // Setup itimer to fire after 500 msecs.
    66    struct itimerval itimer = {};
    67    itimer.it_value.tv_usec = 500 * 1000;  // 500 msecs.
    68    auto const timer_cleanup =
    69        ASSERT_NO_ERRNO_AND_VALUE(ScopedItimer(ITIMER_VIRTUAL, itimer));
    70  
    71    // Initialize %rcx and %r11 and spin until the signal handler returns.
    72    uint64_t rcx = kOrigRcx;
    73    uint64_t r11 = kOrigR11;
    74    asm volatile(
    75        "movq %[rcx], %%rcx;"                      // %rcx = rcx
    76        "movq %[r11], %%r11;"                      // %r11 = r11
    77        "movl $1, %[ready];"                       // ready = 1
    78        "1: pause; cmpl $0, %[gotvtalrm]; je 1b;"  // while (!gotvtalrm);
    79        "movq %%rcx, %[rcx];"                      // rcx = %rcx
    80        "movq %%r11, %[r11];"                      // r11 = %r11
    81        : [ ready ] "=m"(ready), [ rcx ] "+m"(rcx), [ r11 ] "+m"(r11)
    82        : [ gotvtalrm ] "m"(gotvtalrm)
    83        : "cc", "memory", "rcx", "r11");
    84  
    85    // If sigreturn(2) returns via 'sysret' then %rcx and %r11 will be
    86    // clobbered and set to 'ptregs->rip' and 'ptregs->rflags' respectively.
    87    //
    88    // The following check verifies that %rcx and %r11 were not clobbered
    89    // when returning from the signal handler (via sigreturn(2)).
    90    EXPECT_EQ(rcx, ~kOrigRcx);
    91    EXPECT_EQ(r11, ~kOrigR11);
    92  }
    93  
    94  constexpr uint64_t kNonCanonicalRip = 0xCCCC000000000000;
    95  
    96  // Test that a non-canonical signal handler faults as expected.
    97  TEST(SigIretTest, BadHandler) {
    98    struct sigaction sa = {};
    99    sa.sa_sigaction =
   100        reinterpret_cast<void (*)(int, siginfo_t*, void*)>(kNonCanonicalRip);
   101    auto const cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGUSR1, sa));
   102  
   103    pid_t pid = fork();
   104    if (pid == 0) {
   105      // Child, wait for signal.
   106      while (1) {
   107        pause();
   108      }
   109    }
   110    ASSERT_THAT(pid, SyscallSucceeds());
   111  
   112    EXPECT_THAT(kill(pid, SIGUSR1), SyscallSucceeds());
   113  
   114    int status;
   115    EXPECT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   116    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)
   117        << "status = " << status;
   118  }
   119  
   120  }  // namespace
   121  
   122  }  // namespace testing
   123  }  // namespace gvisor
   124  
   125  int main(int argc, char** argv) {
   126    // SigIretTest.CheckRcxR11 depends on delivering SIGVTALRM to the main thread.
   127    // Block SIGVTALRM so that any other threads created by TestInit will also
   128    // have SIGVTALRM blocked.
   129    sigset_t set;
   130    sigemptyset(&set);
   131    sigaddset(&set, SIGVTALRM);
   132    TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0);
   133  
   134    gvisor::testing::TestInit(&argc, &argv);
   135    return gvisor::testing::RunAllTests();
   136  }