gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 }