gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 int ret = testX7(&x7, __NR_tgkill, getpid(), syscall(__NR_gettid), SIGVTALRM); 88 89 EXPECT_EQ(ret, 0); 90 // The following check verifies that %x7 was not clobbered 91 // when returning from the signal handler (via sigreturn(2)). 92 EXPECT_EQ(x7, ~kOrigX7); 93 } 94 95 } // namespace 96 97 } // namespace testing 98 } // namespace gvisor