github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/rseq.cc (about) 1 // Copyright 2019 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 <sys/syscall.h> 18 #include <sys/types.h> 19 #include <sys/wait.h> 20 #include <unistd.h> 21 22 #include "gtest/gtest.h" 23 #include "test/syscalls/linux/rseq/test.h" 24 #include "test/syscalls/linux/rseq/uapi.h" 25 #include "test/util/logging.h" 26 #include "test/util/multiprocess_util.h" 27 #include "test/util/posix_error.h" 28 #include "test/util/test_util.h" 29 30 namespace gvisor { 31 namespace testing { 32 33 namespace { 34 35 using ::testing::AnyOf; 36 using ::testing::Eq; 37 38 // Syscall test for rseq (restartable sequences). 39 // 40 // We must be very careful about how these tests are written. Each thread may 41 // only have one struct rseq registration, which may be done automatically at 42 // thread start (as of 2019-11-13, glibc does *not* support rseq and thus does 43 // not do so, but other libraries do). 44 // 45 // Testing of rseq is thus done primarily in a child process with no 46 // registration. This means exec'ing a nostdlib binary, as rseq registration can 47 // only be cleared by execve (or knowing the old rseq address), and glibc (based 48 // on the current unmerged patches) register rseq before calling main()). 49 50 int RSeq(struct rseq* rseq, uint32_t rseq_len, int flags, uint32_t sig) { 51 return syscall(kRseqSyscall, rseq, rseq_len, flags, sig); 52 } 53 54 // Returns true if this kernel supports the rseq syscall. 55 PosixErrorOr<bool> RSeqSupported() { 56 // We have to be careful here, there are three possible cases: 57 // 58 // 1. rseq is not supported -> ENOSYS 59 // 2. rseq is supported and not registered -> success, but we should 60 // unregister. 61 // 3. rseq is supported and registered -> EINVAL (most likely). 62 63 // The only validation done on new registrations is that rseq is aligned and 64 // writable. 65 rseq rseq = {}; 66 int ret = RSeq(&rseq, sizeof(rseq), 0, 0); 67 if (ret == 0) { 68 // Successfully registered, rseq is supported. Unregister. 69 ret = RSeq(&rseq, sizeof(rseq), kRseqFlagUnregister, 0); 70 if (ret != 0) { 71 return PosixError(errno); 72 } 73 return true; 74 } 75 76 switch (errno) { 77 case ENOSYS: 78 // Not supported. 79 return false; 80 case EINVAL: 81 // Supported, but already registered. EINVAL returned because we provided 82 // a different address. 83 return true; 84 default: 85 // Unknown error. 86 return PosixError(errno); 87 } 88 } 89 90 constexpr char kRseqBinary[] = "test/syscalls/linux/rseq/rseq"; 91 92 void RunChildTest(std::string test_case, int want_status) { 93 std::string path = RunfilePath(kRseqBinary); 94 95 pid_t child_pid = -1; 96 int execve_errno = 0; 97 auto cleanup = ASSERT_NO_ERRNO_AND_VALUE( 98 ForkAndExec(path, {path, test_case}, {}, &child_pid, &execve_errno)); 99 100 ASSERT_GT(child_pid, 0); 101 ASSERT_EQ(execve_errno, 0); 102 103 int status = 0; 104 ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0), SyscallSucceeds()); 105 ASSERT_THAT(status, AnyOf(Eq(want_status), Eq(128 + want_status))); 106 } 107 108 // Test that rseq must be aligned. 109 TEST(RseqTest, Unaligned) { 110 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 111 112 RunChildTest(kRseqTestUnaligned, 0); 113 } 114 115 // Sanity test that registration works. 116 TEST(RseqTest, Register) { 117 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 118 119 RunChildTest(kRseqTestRegister, 0); 120 } 121 122 // Registration can't be done twice. 123 TEST(RseqTest, DoubleRegister) { 124 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 125 126 RunChildTest(kRseqTestDoubleRegister, 0); 127 } 128 129 // Registration can be done again after unregister. 130 TEST(RseqTest, RegisterUnregister) { 131 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 132 133 RunChildTest(kRseqTestRegisterUnregister, 0); 134 } 135 136 // The pointer to rseq must match on register/unregister. 137 TEST(RseqTest, UnregisterDifferentPtr) { 138 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 139 140 RunChildTest(kRseqTestUnregisterDifferentPtr, 0); 141 } 142 143 // The signature must match on register/unregister. 144 TEST(RseqTest, UnregisterDifferentSignature) { 145 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 146 147 RunChildTest(kRseqTestUnregisterDifferentSignature, 0); 148 } 149 150 // The CPU ID is initialized. 151 TEST(RseqTest, CPU) { 152 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 153 154 RunChildTest(kRseqTestCPU, 0); 155 } 156 157 // Critical section is eventually aborted. 158 TEST(RseqTest, Abort) { 159 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 160 161 RunChildTest(kRseqTestAbort, 0); 162 } 163 164 // Abort may be before the critical section. 165 TEST(RseqTest, AbortBefore) { 166 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 167 168 RunChildTest(kRseqTestAbortBefore, 0); 169 } 170 171 // Signature must match. 172 TEST(RseqTest, AbortSignature) { 173 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 174 175 RunChildTest(kRseqTestAbortSignature, SIGSEGV); 176 } 177 178 // Abort must not be in the critical section. 179 TEST(RseqTest, AbortPreCommit) { 180 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 181 182 RunChildTest(kRseqTestAbortPreCommit, SIGSEGV); 183 } 184 185 // rseq.rseq_cs is cleared on abort. 186 TEST(RseqTest, AbortClearsCS) { 187 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 188 189 RunChildTest(kRseqTestAbortClearsCS, 0); 190 } 191 192 // rseq.rseq_cs is cleared on abort outside of critical section. 193 TEST(RseqTest, InvalidAbortClearsCS) { 194 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(RSeqSupported())); 195 196 RunChildTest(kRseqTestInvalidAbortClearsCS, 0); 197 } 198 199 } // namespace 200 201 } // namespace testing 202 } // namespace gvisor