github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/sigreturn_arm64.cc (about)

     1  // Copyright 2021 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 <linux/unistd.h>
    16  #include <signal.h>
    17  #include <sys/syscall.h>
    18  #include <sys/types.h>
    19  #include <sys/ucontext.h>
    20  #include <unistd.h>
    21  
    22  #include "gtest/gtest.h"
    23  #include "test/util/logging.h"
    24  #include "test/util/signal_util.h"
    25  #include "test/util/test_util.h"
    26  #include "test/util/timer_util.h"
    27  
    28  namespace gvisor {
    29  namespace testing {
    30  
    31  namespace {
    32  
    33  constexpr uint64_t kOrigX7 = 0xdeadbeeffacefeed;
    34  
    35  void sigvtalrm(int sig, siginfo_t* siginfo, void* _uc) {
    36    ucontext_t* uc = reinterpret_cast<ucontext_t*>(_uc);
    37  
    38    // Verify that:
    39    // - x7 value in mcontext_t matches kOrigX7.
    40    if (uc->uc_mcontext.regs[7] == kOrigX7) {
    41      // Modify the value x7 in the ucontext. This is the value seen by the
    42      // application after the signal handler returns.
    43      uc->uc_mcontext.regs[7] = ~kOrigX7;
    44    }
    45  }
    46  
    47  int testX7(uint64_t* val, uint64_t sysno, uint64_t tgid, uint64_t tid,
    48             uint64_t signo) {
    49    register uint64_t* x9 __asm__("x9") = val;
    50    register uint64_t x8 __asm__("x8") = sysno;
    51    register uint64_t x0 __asm__("x0") = tgid;
    52    register uint64_t x1 __asm__("x1") = tid;
    53    register uint64_t x2 __asm__("x2") = signo;
    54  
    55    // Initialize x7, send SIGVTALRM to itself and read x7.
    56    __asm__(
    57        "ldr x7, [x9, 0]\n"
    58        "svc 0\n"
    59        "str x7, [x9, 0]\n"
    60        : "=r"(x0)
    61        : "r"(x0), "r"(x1), "r"(x2), "r"(x9), "r"(x8)
    62        : "x7");
    63    return x0;
    64  }
    65  
    66  // On ARM64, when ptrace stops on a system call, it uses the x7 register to
    67  // indicate whether the stop has been signalled from syscall entry or syscall
    68  // exit. This means that we can't get a value of this register and we can't
    69  // change it. More details are in the comment for tracehook_report_syscall in
    70  // arch/arm64/kernel/ptrace.c.
    71  //
    72  // CheckR7 checks that the ptrace platform handles the x7 register properly.
    73  TEST(SigreturnTest, CheckX7) {
    74    // Setup signal handler for SIGVTALRM.
    75    struct sigaction sa = {};
    76    sigfillset(&sa.sa_mask);
    77    sa.sa_sigaction = sigvtalrm;
    78    sa.sa_flags = SA_SIGINFO;
    79    auto const action_cleanup =
    80        ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGVTALRM, sa));
    81  
    82    auto const mask_cleanup =
    83        ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGVTALRM));
    84  
    85    uint64_t x7 = kOrigX7;
    86  
    87    testX7(&x7, __NR_tgkill, getpid(), syscall(__NR_gettid), SIGVTALRM);
    88  
    89    // The following check verifies that %x7 was not clobbered
    90    // when returning from the signal handler (via sigreturn(2)).
    91    EXPECT_EQ(x7, ~kOrigX7);
    92  }
    93  
    94  }  // namespace
    95  
    96  }  // namespace testing
    97  }  // namespace gvisor